Compare commits

...

6 Commits

16 changed files with 902 additions and 11 deletions

4
.gitignore vendored Normal file
View File

@@ -0,0 +1,4 @@
**/render.html
**/render.html.lock
build/

19
Makefile Normal file
View File

@@ -0,0 +1,19 @@
DISTDIR ?= $(shell pwd)
TEMPLATE_DIR ?= $(DISTDIR)/templates
SCRIPT_DIR ?= $(DISTDIR)/scripts
BUILDDIR ?= $(DISTDIR)/build
export
PAGES := $(wildcard pages/*)
all: $(PAGES) static
$(PAGES):
$(MAKE) -C $@
static:
@mkdir -p $(BUILDDIR)
cp -r static $(BUILDDIR)
.PHONY: all $(PAGES) static

View File

@@ -1,7 +0,0 @@
{
"standalone": false,
"template": "basic_template.html",
"credits": [
"Никифор Кузнецов"
]
}

3
pages/linear_nt/Makefile Normal file
View File

@@ -0,0 +1,3 @@
# Default makefile for algorithmica-like pages
include $(SCRIPT_DIR)/mk/algorithmica.mk

View File

@@ -5,14 +5,11 @@
известно, как определить, является ли число простым за полиномиальное время, а найти все простые числа от $1$ до $N$
можно решетом Эратосфена, и даже за линейное время.
Также неизвестна содержательная оценка сверху количества делителей числа, но известна практически точная оценка для суммы
количества делителей по всем числам от $1$ до $N$
**Важное замечание:** далее во всех асимптотиках алгоритмов мы считаем количество арифметических операций. Иначе говоря, мы не берем во внимание, сколько выполняется операция умножения или деления, взятия по модулю.
## Результаты аналитической теории чисел
Которые, мы, однако, доказывать не будем, но будем активно использовать.
Которые, мы, однако, доказывать не будем, но будем активно использовать(здесь $\log$ -- натуральный логарифм)
**Вторая теорема Мертенса**. $$\sum\limits_{p \leqslant n, p \text{ -- простое}} \frac{1}{p} = \log \log n + C + o(1)$$
Доказательство более слабого утверждения можно найти

View File

@@ -0,0 +1,5 @@
---
credits:
- Никифор Кузнецов
title: Линейные алгоритмы в теории чисел
---

View File

@@ -0,0 +1,3 @@
# Default makefile for algorithmica-like pages
include $(SCRIPT_DIR)/mk/algorithmica.mk

View File

@@ -0,0 +1,254 @@
---
header-includes: |
\newcommand{\legendre}[2]{\begin{pmatrix} #1\cr \hdashline #2\cr \end{pmatrix}}
\newcommand{\Zp}{\mathbb{Z}_p}
...
# Квадратичные вычеты и корни по простому модулю
На данный момент статья находится в разработке.
В этой статье вы узнаете всё о квадратичных вычетах по простому модулю и разложении числа в сумму двух квадратов.
Будем считать, что арифметические операции в $\Zp$ работают за константое время или что то же самое, мерять все в арифметических
операциях(сложение, умножение, вычитание).
## Вычеты, символ Лежандра
Здесь и далее $p$ -- простое число.
**Определение**. $p \nmid a \leftarrow \Zp$ называется _квадратичным вычетом_ если существует такое $z$, что $z^2 \equiv a \pmod{p}$, а
иначе евычетом_.
**Определение**. Символом Лежандра числа $a$ называется величина $\legendre{a}{p}$, равная единице, если $a$ является квадратичным
вычетом по модулю $p$, нулю если $a \equiv 0$, и $-1$ иначе.
**Лемма**. В $\Zp$ поровну квадратичных вычетов и невычетов, а именно $\frac{p - 1}{2}$.
**Доказательство**. Посмотрим на числа $1^2, 2^2, \ldots, (p - 1)^2$. Заметим, что $a^2 \equiv b^2$ равносильно тому что $p \mid (a - b)(a + b)$, то есть
либо $a \equiv b$, либо $a \equiv -b$. А это значит, что среди первых $\frac{p - 1}{2}$ квадратов нет повторяющихся, а поскольку $a^2
\equiv (p - a)^2$, то это все квадраты, что и требовалось.
**Лемма**. $\legendre{ab}{p} = \legendre{a}{p} \legendre{b}{p}$.
**Доказательство**. Посмотрим что означает данное утверждение. Оно значит, что произведение двух вычетов является вычетом, произведение двух невычетов также
является вычетом, а вот произведение вычета и невычета является невычетом.
Очевидно, что произведение двух вычетов является вычетом. $a \equiv x^2, b \equiv y^2$, значит $ab \equiv (xy)^2$.
Также понятно про произведение вычета и невычета. Если $a \equiv x^2, ab \equiv y^2$, то $b \equiv \left( \frac{y}{x} \right)^2$, где
$\frac{y}{x} = yx^{-1}$, а $x^{-1}$ обратный остаток к $x$.
Осталось доказать, что произведение двух невычетов является вычетом. Предположим противное. Пусть $c \equiv ab$. Для
каждого $x$ существует единственный $y$ такой, что $xy \equiv c$. Поскольку $c$ не является вычетом все числа можно так разбить на пары.
Но в каждой паре есть хотя бы один невычет из первого пункта доказательства, но в одной из пар два невычета, значит их больше половины, противоречие.
Мы доказали очень важное свойство, которое называется ультипликативностью_.
**Лемма**. $\legendre{a}{p} = a^{\frac{p - 1}{2}}$.
**Доказательство**. Заметим, что если $a \equiv x^2$, то $a^{\frac{p - 1}{2}} \equiv x^{p - 1} \equiv 1$ по малой теореме Ферма, то есть
для вычетов утверждение верно.
Можно было бы сказать, что многочлен $x^{\frac{p - 1}{2}} - 1$ имеет не более $\frac{p - 1}{2}$ корней, потому что $\Zp$ -- поле, но у
этого факта есть более элементарное доказательство.
Проделаем тот же трюк, что и в доказательстве мультипликативности для двух невычетов. Тогда произведение всех чисел в парах с одной
стороны равно $(p - 1)!$, так как каждое число встречается ровно один раз, а с другой стороны $a^{\frac{p - 1}{2}}$, но по теореме
Вильсона $(p - 1)! \equiv -1 \pmod{p}$.
Это знание, например, позволит нам определить когда $-1$ является вычетом, и, даже, если очень постараться, понять то же самое про $2$.
**Лемма**. $-1$ является вычетом тогда и только тогда, когда $p = 4k + 1$.
**Доказательство**. Примените формулу для символа Лежандра.
**Лемма**. $\legendre{2}{p} = (-1)^{\frac{p^2 - 1}{8}}$.
**Доказательство**. Пусть $P = 2 \cdot 4 \cdot \ldots \cdot (p - 1)$. Тогда $P \equiv 2^{\frac{p - 1}{2}} \left(\frac{p - 1}{2}\right)!
\equiv \legendre{2}{p} \left(\frac{p - 1}{2} \right)!$
Сократим общие множители в сравнении и рассмотрим случаи.
__Первый случай__. $p = 4k + 1$. Получаем сравнение
\begin{equation*}
(2k + 2) \cdot \ldots \cdot 4k \equiv \legendre{2}{p} \cdot 1 \cdot 3 \cdot \ldots (2k - 1)
\end{equation*}
Заметим, что
\begin{equation*}
(2k + 2) \cdot \ldots \cdot 4k \equiv (-1)^k \cdot 1 \cdot 4 \cdot \ldots \cdot (2k - 1)
\end{equation*}
Откуда $(-1)^k \equiv \legendre{2}{p}$. Нетрудно проверить, что $k$ и $\frac{p^2 - 1}{8}$ имеют одинаковую четность, что и требовалось.
__Второй случай__. $p = 4k + 3$. Второй случай аналогичен и достается читателю в качестве простого и приятного упражнения.
### Нахождение квадратного корня по модулю
Символ Лежандра числа $a$ можно найти за $O(\log p)$, возведя его в степень $\frac{p - 1}{2}$. А можно ли найти квадратный корень числа
по модулю?
Для начала попробуем найти квадратный корень $-1$, если $p = 4k + 1$. Пусть $a$ -- невычет по модулю $p$, то $a^{\frac{p - 1}{2}} \equiv -1$, а
значит $a^{\frac{p - 1}{4}} \equiv a^k$ это искомый корень. Перед нами встаёт задача о нахождении невычета по модулю $p$.
**Лемма**. Существует алгоритм, который находит невычет по модулю $p$ за ожидаемое время $O(\log p)$.
**Доказательство**. Будем брать случайное число от $1$ до $p - 1$ включительно и проверять является ли оно невычетом, вычисляя символ
Лежандра за $O(\log p)$.
Поскольку невычетов ровно половина, вероятность того, что очередное число окажется невычетом равна $\frac{1}{2}$, а значит
ожидаемое число шагов равно $2$.
Существование полиномиального, детерминированного и безусловного(не опирающегося на недоказанные факты) алгоритма является открытой проблемой.
В предположении гипотезы Римана среди первых $O(\log^2 p)$ чисел есть невычет.
**Лемма**. Если $n$ является вычетом, то существует алгоритм, который за ожидаемое время $O(\log p)$ находит такое $a$, что $a^2 - n$
является невычетом.
**Доказательство**. Если $n$ вычет, то $n = x^2$, а тогда $a^2 - n = a^2 - x^2 = (a - x)(a + x)$. Воспользуемся мультипликативностью
символа Лежандра, в предположении, что $a + x$ не равно нулю по модулю $p$.
\begin{equation*}
\legendre{a^2 - n}{p} = \legendre{(a - x)(a + x)}{p} = \legendre{a - x}{p} \legendre{a + x}{p} = \frac{\legendre{a - x}{p}}{\legendre{a +
x}{p}} = \legendre{\dfrac{a - x}{a + x}}{p}
\end{equation*}
Обозначим $f(a) = \dfrac{a - x}{a + x}$. Пусть $f(a) \equiv f(b)$. Тогда
\begin{equation*}
\dfrac{a - x}{a + x} \equiv \dfrac{b - x}{b + x}
\end{equation*}
\begin{equation*}
(a - x)(b + x) \equiv (a + x)(b - x)
\end{equation*}
\begin{equation*}
ab - bx + ax - x^2 \equiv ab + bx - ax - x^2
\end{equation*}
\begin{equation*}
(a - b)x \equiv (b - a)x
\end{equation*}
То есть $f(a) \equiv f(b) \Longrightarrow a \equiv b$.
Поскольку $\legendre{a^2 - n}{p} = \legendre{f(a)}{p}$, то вероятность того, что случайно выбранное $a$ окажется подходящим равна
вероятности того, что $f(a)$ является невычетом. Но как было показано ранее, для разных аргументов $f$ возвращает разные значения, а
значит $f$ равновероятно распределена между какими-то $p - 1$ значениями.
Среди любых $p - 1$ остатков хотя бы $\frac{p - 1}{2} - 1$ невычетов. Можно понять это так, мы берем все остатки, и исключаем из них
один, а изначально невычетов $\frac{p - 1}{2}$. Таким образом вероятность того, что $f(a)$ невычет не меньше $\frac{p - 3}{2p - 2}$.
То есть если мы будем выбирать $a$ случайно от 0 до $p$ невключительно, то ожидаемое количество шагов при $p > 3$ ограничено константой.
Можно убедиться, что при $p = 3$ мы сможем найти такое $a$. Действительно, единственный вычет это $1$, то есть $n = 1$. Тогда подходящее $a = 0$.
**Лемма**. Существует алгоритм, который для вычета $n$ ищет такой $z$, что $z^2 \equiv n \pmod{p}$ за ожидаемое время $O(\log p)$.
**Доказательство**. Найдём такое $a$, что $a^2 - n$ является невычетом за ожидаемое время $O(\log p)$. Обозначим за $\omega = \sqrt{a^2 - n}$.
Строго говоря, посмотрим на все многочлены в $\Zp$ от $\omega$. и посмотрим на них по модулю $\omega^2 - (a^2 - n)$. Получившееся
множество $\{ a + bw \mid a, b \leftarrow \Zp \}$ будем обозначать $T = \Zp[w]/(w^2 - (a^2 - n))$.
Заметим, что числа из $T$ можно складывать и умножать: $$(a + bw) + (c + dw) = (a + c) + (b + d)w, (a + bw)(c + dw) = (ac + bd(a^2 - n)) +
(ad + bc)w$$
Понятно, что сложение и умножение обладает всеми необходимыми свойствами(коммутативность, дистрибутивность, ассоциативность)
В качестве упражнения читателю остается проверить, что $T$ -- поле. Из содержательных свойств надо проверить обратимость умножения.
**Лемма**. $(a + w)^{\frac{p + 1}{2}}$ является искомым $z$, что в частности значит, что оно не имеет компоненту с $w$.
**Доказательство**. Посмотрим на $(a + w)^{p + 1}$. Заметим, что $(a + w)^p = a^p + w^p$. Действительно, если раскрыть скобки по биному
Ньютона, то все остальные члены будут делиться на $p$. Также $w^p = -w$, поскольку $w^{p - 1} = (a^2 - n)^\frac{p - 1}{2} = -1$, в силу
того, что $a^2 - n$ невычет. Тогда
\begin{equation*}
(a + w)^{p + 1} = (a^p + w^p)(a + w) = (a - w)(a + w) = a^2 - w^2 = a^2 - (a^2 - n) = n
\end{equation*}
Поскольку читатель проверил, что $T$ является полем, многочлен $x^2 - n$ имеет в нем не более двух корней. Но мы знаем, что $z$ и $-z$
являются его корнями. В то же время $\left((a + w)^\frac{p + 1}{2}\right)^2 - n = 0$, значит оно и есть искомое $z$.
Итого мы доказали очень простой алгоритм для нахождения квадратного корня по модулю.
1. Найти такое $a$, что $a^2 - n$ является невычетом методом проб и ошибок
2. Возвести $(a + w)$ в степень $\frac{p + 1}{2}$ быстрым возведением в степень, где $w = \sqrt{a^2 - n}$, это и будет результатом.
## Разложение в сумму двух квадратов
Наша цель, понять, для каких $n$ существуют $a, b$, такие, что $a^2 + b^2 = n$, и как их оптимально искать.
Для начала попробуем решить задачу для простого $p$. Сразу понятно, что если $p = 4k + 3$, то разложить в сумму двух квадратов не
удастся, можно даже доказать более сильное утверждение.
**Лемма Жирара**. Если $a^2 + b^2 \equiv 0 \pmod{p}$, где $p$ простое число вида $4k + 3$, то $p \mid a, b$.
**Доказательство**. $a^2 \equiv -b^2 \pmod{p}$. Возьмём символ лежандра от обоих частей и воспользуемся мультипликативностью.
\begin{equation*}
\legendre{a^2}{p} = \left[\legendre{a^2}{p} = \legendre{-b^2}{p}\right] = \legendre{-1}{p} \legendre{b^2}{p} = -1 \legendre{b^2}{p}
\end{equation*}
Последнее равенство в силу того, что $p = 4k + 3$. Но тогда $\legendre{a^2}{p} = \legendre{b^2}{p} = 0$, что и требовалось.
**Лемма**. Любое простое $p$ вида $4k + 1$ представляется в виде суммы двух квадратов.
Попробуем конструктивно научиться искать разложение для $p = 4k + 1$. Для начала поймем как "перемножать" квадратичные формы,
это также поможет нам далее, когда мы перейдем в составному $n$.
Пусть $a^2 + b^2 = x, c^2 + d^2 = y$. Тогда
\begin{equation*}
a^2c^2 + a^2d^2 + b^2c^2 + b^2d^2 = xy
\end{equation*}
\begin{equation*}
(ac)^2 + (ad)^2 + (bc)^2 + (bd)^2 = xy
\end{equation*}
\begin{equation*}
(ac)^2 + (bd)^2 + 2abcd + (ad)^2 + (bc)^2 - 2abcd = xy
\end{equation*}
\begin{equation*}
(ac + bd)^2 + (ad - bc)^2 = xy
\end{equation*}
То есть мы доказали, что если $x, y$ представимы в виде суммы двух квадратов, то $xy$ тоже представимо в виде суммы двух квадратов.
Попробуем представить число $p$, пользуясь предыдущим знанием. Пусть для начала у нас есть разбиение числа $mp$ для какого-то $m$, то
есть $a^2 + b^2 = mp$.
**Определение**. _Абсолютно наименьшим вычетом_ числа $a$ по модулю $m$ называется наименьшее по абсолютному значению $b$ такое, что
$a \equiv b \pmod{m}$.
Пусть $c, d$ _абсолютно наименьшие вычеты_ чисел $a, b$ по модулю $m$. Тогда $c^2 + d^2 = mk$ и $k \leqslant \frac{m}{2}$.
Тогда мы можем представить $m^2pk = (ac + bd)^2 + (ad - bc)^2$. Остается только заметить, что $ad - bc$ и $ac + bd$ делятся на $m$.
Действительно, $ad - bc \equiv ab - ab \equiv 0 \pmod{m}$ и $ac + bd \equiv a^2 + b^2 \equiv 0 \pmod{m}$.
\begin{equation*}
pk = \left( \dfrac{ad - bc}{m} \right)^2 + \left( \dfrac{ac + bd}{m} \right)^2
\end{equation*}
Если мы будем повторять эту процедуру, то на каждом шаге $m$ будет уменьшаться хотя бы в два раза, а значит когда-то станет единицей, и
мы получим требуемое разбиение.
Тем самым мы не только доказали лемму, но и нашли эффективный алгоритм нахождения такого разложения.
### Анализ алгоритма
В качестве начального разбиения можно взять $a = 1, b = z$, где $z^2 \equiv -1 \pmod{p}$. Найти $z$ можно за $O(\log p)$.
Далее мы делаем $O(\log p)$ шагов, так как начальное $m$ не превосходит $p$, на каждом шаге делаем константное число операций.
Итого за $O(\log p)$ времени и $O(1)$ дополнительной памяти мы умеем искать разложение $p$ в сумму двух квадратов.
### Составное $n$
Самое интересное происходит в случае составного $n$. Оказывается верно следующее.
**Рождественская теорема Ферма**. Число $n$ можно представить в виде суммы двух квадратов тогда и только тогда, когда каждое простое $p$
вида $4k + 3$ входит в разложение $n$ в четной степени.
В одну сторону мы уже умеем доказывать и находить разбиение. Действительно $2 = 1^2 + 1^2, p^2 = 0^2 + p^2$. Для простых вида $4k + 1$
мы умеем находить разбиение, а ещё мы умеем перемножать два существующих.
**Лемма**. Для любого простого $p$ вида $4k + 3$ его степень вхождения в $a^2 + b^2$ чётна.
**Доказательство**. Если $a^2 + b^2$ не делится на $p$, то утверждение очевидно. Иначе воспользуемся леммой Жирара, получим что $p \mid
a, b$. Тода $p^2 \mid a^2 + b^2$ и $\left( \frac{a}{p} \right)^2 + \left( \frac{b}{p} \right)^2 = \frac{a^2 + b^2}{p^2}$. Применяя то же
самое рассуждение получаем требуемое.

View File

@@ -0,0 +1,5 @@
---
credits:
- Никифор Кузнецов
title: Квадратичные вычеты и корни по простому модулю
---

View File

@@ -0,0 +1,12 @@
TEMPLATE := $(TEMPLATE_DIR)/algorithmica.html
METADATA := $(METADATA) metadata.md
PAGE := $(shell basename $(shell pwd))
all: $(BUILDDIR)/page/$(PAGE)/index.html
$(BUILDDIR)/page/$(PAGE)/index.html: main.md $(TEMPLATE) $(METADATA)
@mkdir -p $(@D)
pandoc $< $(METADATA) --to html --output $@ --standalone --template $(TEMPLATE) --mathjax
.PHONY: all

576
static/css/pandoc.css Normal file
View File

@@ -0,0 +1,576 @@
/*
* Forked from https://gist.github.com/killercup/5917178
*/
@font-face {
font-family: 'CMU';
src: url('/static/fonts/cmu.woff2');
}
@font-face {
font-family: 'Lora';
src: url('/static/fonts/lora.ttf');
}
@font-face {
font-family: 'Inconsolata';
src: url('/static/fonts/inconsolata.woff2');
}
@font-face {
font-family: 'Garamond';
src: url('/static/fonts/garamond.woff2');
}
@font-face {
font-family: "Open Sans";
src: url('/static/fonts/opensans.woff2');
}
html {
font-size: 100%;
overflow-y: scroll;
-webkit-text-size-adjust: 100%;
-ms-text-size-adjust: 100%;
}
a {
white-space: pre; /* for some weird reason this affects pre blocks */
}
/* BEGIN ALGORITHMICA OLD STYLE */
.pagebody {
/* color: #444; */
font-family: "Times New Roman", Times, "Tinos", serif;
font-size: 16px;
line-height: 1.7;
padding: 8px;
margin: auto;
max-width: 750px;
background: #fefefe;
text-align: justify;
padding-bottom: 25px;
}
.pagebody .credits {
font-size: 14px;
margin: 25px 10px -40px 15px;
padding: 16px 50px 0 50px;
/* text-align: left; */
border-top: 1px solid #666;
color: black;
}
.pagebody .credits table {
border: none;
margin-left: 46px;
margin-bottom: 10px;
}
.pagebody .credits table td{
border: none;
padding: 0;
padding-left: 1.5em;
}
.pagebody #header {
height: 55px;
margin-top: -8px;
margin-bottom: 20px;
border-bottom: 1px solid #666;
}
.pagebody #links {
display: inline-block;
text-align: right;
font-size: 16px;
float: right;
margin-top: 17px;
margin-right: 12px;
}
.pagebody #links a {
margin-left: 20px;
}
.pagebody #header a:hover {
color: #0645ad!important;
}
.pagebody #header a {
color: #111 !important;
display: inline-block;
}
.pagebody #logo {
margin-top: 10px;
font-size: 22px;
height: 0;
font-family: 'Garamond', serif;
}
.pagebody .contents {
position: inline-block;
float: left;
position: relative;
left: 12px;
width: 285px;
text-align: left;
}
.pagebody .contents ul {
padding-left: 22px;
margin-top: 10px;
list-style-type: none;
}
.pagebody .contents li {
font-size: 8px;
color: lightgrey;
font-family: 'Open Sans', sans;
height: 30px;
line-height: 8px;
list-style-type: none;
white-space: pre-line;
}
.pagebody .contents li:hover {
color: black;
}
.pagebody .contents li:first-letter {
font-size: 13px;
height: 0;
}
.pagebody .contents a {
font-family: "Times New Roman", Times, "Tinos", serif;
font-size: 16px;
line-height: 1em;
display: inline-block;
width: 252px;
}
.pagebody .contents a:first-letter {
font-size: 16px; /* the only way to fix */
}
.pagebody .contents a:after {
content: "\A";
white-space: pre;
}
.pagebody .contents li:before {
content: '•';
display: inline-block;
position: absolute;
left: 11px;
margin-top: 5px;
color: black !important;
font-size: 18px;
}
.pagebody a {
color: #0645ad;
text-decoration: none;
}
.pagebody a:visited {
color: #0b0080;
}
.pagebody a:hover {
color: #06e;
}
.pagebody a:active {
color: #faa700;
}
.pagebody a:focus {
outline: thin dotted;
}
.pagebody p {
margin: 0.5em 0;
}
.pagebody img {
max-width: 100%;
}
.pagebody .title {
display: none;
}
.pagebody h1 {
text-align: center;
margin-bottom: 0.8em !important;
}
.pagebody h1, h2, h3, h4, h5, h6 {
font-family: 'Garamond', serif;
color: #111;
line-height: 125%;
margin-top: 1em;
margin-bottom: 0em;
font-weight: normal;
}
.pagebody h2, h3 {
padding-bottom: 5px;
border-bottom: 1px solid #eaecef;
}
.pagebody .contents h2, .contents h3 {
padding-bottom: 0;
border-bottom: none;
margin-top: 5px;
}
.pagebody h4, h5, h6 {
font-weight: bold;
}
.pagebody h1 {
font-size: 2.5em;
margin-top: 0.8em;
}
.pagebody h2 {
font-size: 2em;
}
.pagebody h3 {
font-size: 1.5em;
}
.pagebody h4 {
font-size: 1.2em;
}
.pagebody h5 {
font-size: 1em;
}
.pagebody h6 {
font-size: 0.9em;
}
.pagebody blockquote {
color: #666666;
margin: 0;
padding-left: 1em;
border-left: 0.5em #EEE solid;
}
.pagebody hr {
display: block;
width: 100%;
height: 0px;
border: 0;
margin: 0;
padding: 0;
clear: both;
}
.pagebody pre, code, kbd, samp {
color: #000;
font-family: 'Inconsolata', monospace;
}
.pagebody pre {
white-space: pre;
white-space: pre-wrap;
word-wrap: break-word;
}
.pagebody b, strong {
font-weight: bold;
}
.pagebody dfn {
font-style: italic;
}
.pagebody ins {
background: #ff9;
color: #000;
text-decoration: none;
}
.pagebody mark {
background: #ff0;
color: #000;
font-style: italic;
font-weight: bold;
}
.pagebody sub, sup {
font-size: 75%;
line-height: 0;
position: relative;
vertical-align: baseline;
}
.pagebody sup {
top: -0.5em;
}
.pagebody sub {
bottom: -0.25em;
}
.pagebody ul, ol {
margin: 1em 0;
padding: 0 0 0 2em;
}
.pagebody li p:last-child {
margin-bottom: 0;
}
.pagebody li ul {
padding-left: 18px;
padding-top: 1px;
}
.pagebody ul ul, ol ol {
margin: .3em 0;
}
.pagebody dl {
margin-bottom: 1em;
}
.pagebody dt {
font-weight: bold;
margin-bottom: .8em;
}
.pagebody dd {
margin: 0 0 .8em 2em;
}
.pagebody dd:last-child {
margin-bottom: 0;
}
.pagebody img {
border: 0;
-ms-interpolation-mode: bicubic;
vertical-align: middle;
}
.pagebody figure {
display: block;
text-align: center;
margin: 1em 0;
}
.pagebody img {
border: none;
margin: auto;
display: block;
max-width: 85%;
max-height: 320px;
}
.pagebody figcaption {
font-size: 0.8em;
font-style: italic;
margin: 0 0 .8em;
}
.pagebody table {
margin-bottom: 2em;
border-bottom: 1px solid #ddd;
border-right: 1px solid #ddd;
border-spacing: 0;
border-collapse: collapse;
}
.pagebody table th {
padding: .2em 1em;
background-color: #eee;
border-top: 1px solid #ddd;
border-left: 1px solid #ddd;
}
.pagebody table td {
padding: .2em 1em;
border-top: 1px solid #ddd;
border-left: 1px solid #ddd;
vertical-align: top;
}
.pagebody .author {
display: block;
width: 100%;
text-align: right;
margin-top: -30px;
margin-bottom: 40px;
padding-right: 20px;
/* position: absolute; */
color: #444;
font-size: 0.8em;
}
.pagebody code:not([class]) {
border: 1px solid #ddd !important;
background-color: #f8f8f8 !important;
border-radius: 3px !important;
padding-left: 2px !important;
padding-right: 2px !important;
font-size: 0.85em;
}
.pagebody pre {
border: 1px solid #ddd !important;
background-color: #f8f8f8 !important;
border-radius: 3px !important;
padding: 2px !important;
padding-left: 8px !important;
font-size: 0.9em;
}
@media print {
.pagebody {
font-size: 12pt;
width: 190mm;
margin: 0;
/*margin-left 10mm;*/
}
@page { margin: 15mm; }
#header {
display: none;
}
.pagebody pre, ul, ol {
page-break-inside: avoid;
}
.pagebody h1::after, h2::after, h3::after {
/* page-break-after: avoid; */
content: "";
display: block;
height: 100px;
margin-bottom: -100px;
}
/*
h1::before, h2::before, h3::before {
content: "";
display: block;
height: 100px;
margin-top: 100px;
}
*/
.pagebody a, a:visited {
text-decoration: underline;
}
/*
abbr[title]:after {
content: " (" attr(title) ")";
}
*/
.pagebody p, h2, h3 {
orphans: 3;
widows: 3;
}
}
.pagebody a[href^='https://neerc.ifmo.ru']:before {
content: url('https://neerc.ifmo.ru/favicon.ico');
margin-right: 4px;
position: relative;
top: 4px;
}
.pagebody a[href^='https://codeforces.com']:before {
content: url('http://codeforces.com/favicon.ico');
margin-right: 4px;
}
.pagebody a[href=''] {
color: black;
cursor: default;
}
/* END OLD ALGORITHMICA STYLE */
/* BEGIN PANDOC EMBEDDED STYLE FOR CODE */
.pagebody code{white-space: pre-wrap;}
.pagebody span.smallcaps{font-variant: small-caps;}
.pagebody span.underline{text-decoration: underline;}
.pagebody div.column{display: inline-block; vertical-align: top; width: 50%;}
.pagebody div.hanging-indent{margin-left: 1.5em; text-indent: -1.5em;}
.pagebody ul.task-list{list-style: none;}
.pagebody pre > code.sourceCode { white-space: pre; position: relative; }
.pagebody pre > code.sourceCode > span { display: inline-block; line-height: 1.25; }
.pagebody pre > code.sourceCode > span:empty { height: 1.2em; }
.pagebody .sourceCode { overflow: visible; }
.pagebody code.sourceCode > span { color: inherit; text-decoration: inherit; }
.pagebody div.sourceCode { margin: 1em 0; }
.pagebody pre.sourceCode { margin: 0; }
@media screen {
.pagebody div.sourceCode { overflow: auto; }
}
@media print {
.pagebody pre > code.sourceCode { white-space: pre-wrap; }
.pagebody pre > code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
}
.pagebody pre.numberSource code { counter-reset: source-line 0; }
.pagebody pre.numberSource code > span { position: relative; left: -4em; counter-increment: source-line; }
.pagebody pre.numberSource code > span > a:first-child::before { content: counter(source-line);
position: relative; left: -1em; text-align: right; vertical-align: baseline;
border: none; display: inline-block;
-webkit-touch-callout: none; -webkit-user-select: none;
-khtml-user-select: none; -moz-user-select: none;
-ms-user-select: none; user-select: none;
padding: 0 4px; width: 4em;
color: #aaaaaa;
}
.pagebody pre.numberSource { margin-left: 3em; border-left: 1px solid #aaaaaa; padding-left: 4px; }
.pagebody div.sourceCode { }
@media screen {
.pagebody pre > code.sourceCode > span > a:first-child::before { text-decoration: underline; }
}
.pagebody code span.al { color: #ff0000; font-weight: bold; } /* Alert */
.pagebody code span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
.pagebody code span.at { color: #7d9029; } /* Attribute */
.pagebody code span.bn { color: #40a070; } /* BaseN */
.pagebody code span.bu { } /* BuiltIn */
.pagebody code span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
.pagebody code span.ch { color: #4070a0; } /* Char */
.pagebody code span.cn { color: #880000; } /* Constant */
.pagebody code span.co { color: #60a0b0; font-style: italic; } /* Comment */
.pagebody code span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
.pagebody code span.do { color: #ba2121; font-style: italic; } /* Documentation */
.pagebody code span.dt { color: #902000; } /* DataType */
.pagebody code span.dv { color: #40a070; } /* DecVal */
.pagebody code span.er { color: #ff0000; font-weight: bold; } /* Error */
.pagebody code span.ex { } /* Extension */
.pagebody code span.fl { color: #40a070; } /* Float */
.pagebody code span.fu { color: #06287e; } /* Function */
.pagebody code span.im { } /* Import */
.pagebody code span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
.pagebody code span.kw { color: #007020; font-weight: bold; } /* Keyword */
.pagebody code span.op { color: #666666; } /* Operator */
.pagebody code span.ot { color: #007020; } /* Other */
.pagebody code span.pp { color: #bc7a00; } /* Preprocessor */
.pagebody code span.sc { color: #4070a0; } /* SpecialChar */
.pagebody code span.ss { color: #bb6688; } /* SpecialString */
.pagebody code span.st { color: #4070a0; } /* String */
.pagebody code span.va { color: #19177c; } /* Variable */
.pagebody code span.vs { color: #4070a0; } /* VerbatimString */
.pagebody code span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
/* END PANDOC EMBEDDED STYLE FOR CODE */

BIN
static/fonts/cmu.woff2 Normal file

Binary file not shown.

BIN
static/fonts/garamond.woff2 Normal file

Binary file not shown.

Binary file not shown.

BIN
static/fonts/opensans.woff2 Normal file

Binary file not shown.

View File

@@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="ru">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="/static/css/pandoc.css">
<script src="https://polyfill.io/v3/polyfill.min.js?features=es6"></script>
<script id="MathJax-script" async src="https://cdn.jsdelivr.net/npm/mathjax@3/es5/tex-mml-chtml.js"></script>
<title> $title$ </title>
</head>
<body>
<div class="pagehead">
</div>
<div class="pagebody">
$body$
</div>
</body>
</html>