├── build.bat ├── build.py ├── course_pdf ├── HSE_Algo_2019__seminar_10__heaps.pdf ├── HSE_Algo_2019__seminar_14__splay__together_.pdf ├── HSE_Algo_2019__seminar_15__range_queries__together_.pdf ├── HSE_Algo_2019__seminar_2__probabilities_.pdf ├── HSE_Algo_2019__seminar_3__expectations_.pdf ├── HSE_Algo_2019__seminar_4__probab.pdf ├── HSE_Algo_2019__seminar_6__sorting__together_.pdf ├── HSE_Algo_2019__seminar_7__sorting_2__together_.pdf └── HSE_Algo_2019__seminar_9__ordere.pdf ├── pdf_files ├── lec_01_2210.pdf ├── lec_02_2910.pdf ├── lec_03_0511.pdf ├── lec_04_1211.pdf ├── lec_05_1411.pdf ├── lec_06_1911.pdf ├── lec_07_2611.pdf ├── lec_08_2711.pdf ├── lec_08_2811.pdf ├── lec_09_0312.pdf ├── lec_10_1012.pdf ├── lec_11_1212.pdf ├── lec_12_1712.pdf ├── lec_12_1812.pdf ├── lec_13_1401.pdf ├── lec_14_1601.pdf ├── lec_15_2301.pdf ├── lec_16_2801.pdf ├── lec_17_3001.pdf ├── lec_18_0602.pdf ├── lec_19_1102.pdf ├── lec_20_1003.pdf ├── lec_20_1302.pdf ├── lec_21_2002.pdf ├── lec_22_2502.pdf ├── lec_23_2702.pdf ├── lec_24_0503.pdf ├── lec_25_1003.pdf ├── lec_26_1203.pdf ├── lec_27_0704.pdf ├── lec_28_1404.pdf ├── lec_29_1604.pdf ├── lec_30_2104.pdf ├── lec_31_2804.pdf ├── lec_32_3004.pdf ├── lec_33_1205.pdf ├── lec_34_1405.pdf ├── lec_35_1905.pdf ├── lec_36_2605.pdf ├── lec_37_2805.pdf ├── lec_38_0206.pdf ├── lec_39_0906.pdf ├── lectures.pdf ├── sem_01_2210.pdf ├── sem_04_1211.pdf ├── sem_12_1712.pdf ├── sem_13_1401.pdf ├── sem_14_1405.pdf └── seminars.pdf ├── pictures ├── binoial_heap.png ├── binominial_heap.png ├── binominial_heap_add.png ├── euler_path_on_tree.png ├── pointer_machine.jpeg └── segtree.png ├── tex_files ├── lec_01_2210.tex ├── lec_02_2910.tex ├── lec_03_0511.tex ├── lec_04_1211.tex ├── lec_05_1411.tex ├── lec_06_1911.tex ├── lec_07_2611.tex ├── lec_08_2711.tex ├── lec_08_2811.tex ├── lec_09_0312.tex ├── lec_10_1012.tex ├── lec_11_1212.tex ├── lec_12_1712.tex ├── lec_12_1812.tex ├── lec_13_1401.tex ├── lec_14_1601.tex ├── lec_15_2301.tex ├── lec_16_2801.tex ├── lec_17_3001.tex ├── lec_18_0602.tex ├── lec_19_1102.tex ├── lec_20_1302.tex ├── lec_21_2002.tex ├── lec_22_2502.tex ├── lec_23_2702.tex ├── lec_24_0503.tex ├── lec_25_1003.tex ├── lec_26_1203.tex ├── lec_27_0704.tex ├── lec_28_1404.tex ├── lec_29_1604.tex ├── lec_30_2104.tex ├── lec_31_2804.tex ├── lec_32_3004.tex ├── lec_33_1205.tex ├── lec_34_1405.tex ├── lec_35_1905.tex ├── lec_36_2605.tex ├── lec_37_2805.tex ├── lec_38_0206.tex ├── lec_39_0906.tex ├── sem_01_2210.tex ├── sem_04_1211.tex ├── sem_12_1712.tex ├── sem_13_1401.tex └── sem_14_1405.tex └── union.sh /build.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | for /r tex_files %%i in (*) do ( 4 | pdflatex -shell-escape -synctex=1 %%i 5 | move %%~ni.pdf pdf_files 6 | del %%~ni* 7 | ) 8 | 9 | for /f %%i in ('dir /a:d /b _minted*') do rmdir /s /q %%~ni 10 | del *.log 11 | -------------------------------------------------------------------------------- /build.py: -------------------------------------------------------------------------------- 1 | from os import popen 2 | from os import system 3 | 4 | dirs = popen('ls tex_files').read().split() 5 | for filename in dirs: 6 | filename = filename[:-4] 7 | system('pdflatex -shell-escape -synctex=1 tex_files/' + filename + '.tex') 8 | system('mv ' + filename + '.pdf pdf_files') 9 | system('rm ' + filename + '*') 10 | system('rm -rf _minted*') 11 | system('rm *.log') -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_10__heaps.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_10__heaps.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_14__splay__together_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_14__splay__together_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_15__range_queries__together_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_15__range_queries__together_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_2__probabilities_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_2__probabilities_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_3__expectations_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_3__expectations_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_4__probab.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_4__probab.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_6__sorting__together_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_6__sorting__together_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_7__sorting_2__together_.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_7__sorting_2__together_.pdf -------------------------------------------------------------------------------- /course_pdf/HSE_Algo_2019__seminar_9__ordere.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/course_pdf/HSE_Algo_2019__seminar_9__ordere.pdf -------------------------------------------------------------------------------- /pdf_files/lec_01_2210.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_01_2210.pdf -------------------------------------------------------------------------------- /pdf_files/lec_02_2910.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_02_2910.pdf -------------------------------------------------------------------------------- /pdf_files/lec_03_0511.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_03_0511.pdf -------------------------------------------------------------------------------- /pdf_files/lec_04_1211.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_04_1211.pdf -------------------------------------------------------------------------------- /pdf_files/lec_05_1411.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_05_1411.pdf -------------------------------------------------------------------------------- /pdf_files/lec_06_1911.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_06_1911.pdf -------------------------------------------------------------------------------- /pdf_files/lec_07_2611.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_07_2611.pdf -------------------------------------------------------------------------------- /pdf_files/lec_08_2711.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_08_2711.pdf -------------------------------------------------------------------------------- /pdf_files/lec_08_2811.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_08_2811.pdf -------------------------------------------------------------------------------- /pdf_files/lec_09_0312.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_09_0312.pdf -------------------------------------------------------------------------------- /pdf_files/lec_10_1012.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_10_1012.pdf -------------------------------------------------------------------------------- /pdf_files/lec_11_1212.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_11_1212.pdf -------------------------------------------------------------------------------- /pdf_files/lec_12_1712.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_12_1712.pdf -------------------------------------------------------------------------------- /pdf_files/lec_12_1812.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_12_1812.pdf -------------------------------------------------------------------------------- /pdf_files/lec_13_1401.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_13_1401.pdf -------------------------------------------------------------------------------- /pdf_files/lec_14_1601.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_14_1601.pdf -------------------------------------------------------------------------------- /pdf_files/lec_15_2301.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_15_2301.pdf -------------------------------------------------------------------------------- /pdf_files/lec_16_2801.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_16_2801.pdf -------------------------------------------------------------------------------- /pdf_files/lec_17_3001.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_17_3001.pdf -------------------------------------------------------------------------------- /pdf_files/lec_18_0602.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_18_0602.pdf -------------------------------------------------------------------------------- /pdf_files/lec_19_1102.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_19_1102.pdf -------------------------------------------------------------------------------- /pdf_files/lec_20_1003.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_20_1003.pdf -------------------------------------------------------------------------------- /pdf_files/lec_20_1302.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_20_1302.pdf -------------------------------------------------------------------------------- /pdf_files/lec_21_2002.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_21_2002.pdf -------------------------------------------------------------------------------- /pdf_files/lec_22_2502.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_22_2502.pdf -------------------------------------------------------------------------------- /pdf_files/lec_23_2702.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_23_2702.pdf -------------------------------------------------------------------------------- /pdf_files/lec_24_0503.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_24_0503.pdf -------------------------------------------------------------------------------- /pdf_files/lec_25_1003.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_25_1003.pdf -------------------------------------------------------------------------------- /pdf_files/lec_26_1203.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_26_1203.pdf -------------------------------------------------------------------------------- /pdf_files/lec_27_0704.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_27_0704.pdf -------------------------------------------------------------------------------- /pdf_files/lec_28_1404.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_28_1404.pdf -------------------------------------------------------------------------------- /pdf_files/lec_29_1604.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_29_1604.pdf -------------------------------------------------------------------------------- /pdf_files/lec_30_2104.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_30_2104.pdf -------------------------------------------------------------------------------- /pdf_files/lec_31_2804.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_31_2804.pdf -------------------------------------------------------------------------------- /pdf_files/lec_32_3004.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_32_3004.pdf -------------------------------------------------------------------------------- /pdf_files/lec_33_1205.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_33_1205.pdf -------------------------------------------------------------------------------- /pdf_files/lec_34_1405.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_34_1405.pdf -------------------------------------------------------------------------------- /pdf_files/lec_35_1905.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_35_1905.pdf -------------------------------------------------------------------------------- /pdf_files/lec_36_2605.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_36_2605.pdf -------------------------------------------------------------------------------- /pdf_files/lec_37_2805.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_37_2805.pdf -------------------------------------------------------------------------------- /pdf_files/lec_38_0206.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_38_0206.pdf -------------------------------------------------------------------------------- /pdf_files/lec_39_0906.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lec_39_0906.pdf -------------------------------------------------------------------------------- /pdf_files/lectures.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/lectures.pdf -------------------------------------------------------------------------------- /pdf_files/sem_01_2210.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/sem_01_2210.pdf -------------------------------------------------------------------------------- /pdf_files/sem_04_1211.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/sem_04_1211.pdf -------------------------------------------------------------------------------- /pdf_files/sem_12_1712.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/sem_12_1712.pdf -------------------------------------------------------------------------------- /pdf_files/sem_13_1401.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/sem_13_1401.pdf -------------------------------------------------------------------------------- /pdf_files/sem_14_1405.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/sem_14_1405.pdf -------------------------------------------------------------------------------- /pdf_files/seminars.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pdf_files/seminars.pdf -------------------------------------------------------------------------------- /pictures/binoial_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/binoial_heap.png -------------------------------------------------------------------------------- /pictures/binominial_heap.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/binominial_heap.png -------------------------------------------------------------------------------- /pictures/binominial_heap_add.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/binominial_heap_add.png -------------------------------------------------------------------------------- /pictures/euler_path_on_tree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/euler_path_on_tree.png -------------------------------------------------------------------------------- /pictures/pointer_machine.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/pointer_machine.jpeg -------------------------------------------------------------------------------- /pictures/segtree.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MakArtKar/algos_lectures/5d0ccdb32c11aee698be817d3d5920865bf8e2e0/pictures/segtree.png -------------------------------------------------------------------------------- /tex_files/lec_01_2210.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Макоян Артем, ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Лекция по АиСД 22.10} 65 | 66 | \begin{document} 67 | 68 | 69 | \large 70 | 71 | \tu{Формула оценки}: \tb{0.25 дз + 0.3 контест + 0.15 кр + 0.3 экзамен + Бонус} 72 | 73 | \tu{Домашние задания}: сдавать устно(раз в неделю ассисты устраивают доп пару, запись онлайн) или latex, дедлайн 10-21 день. 74 | 75 | \tu{Контесты}: Длинные(код ревью), короткие(раз в 2 недели), неточные, бонусные(идет к бонусу). Штрафов нет. 76 | 77 | \tu{Контрольные работы}: раз в модуль, тестовые вопросы. 78 | 79 | \tu{Бонусы}: бонусные контесты, ACM, работа на семинаре. 80 | 81 | \tu{Материалы}: 82 | \begin{itemize} 83 | \item Кормен 84 | \item en.wikipedia 85 | \item викиконспекты 86 | \item e-maxx 87 | \item Корте-Фанен Коммбинаторная оптимизация 88 | \end{itemize} 89 | 90 | \tb{Теория вероятности}. 91 | $(\Omega, 2^{\Omega}, P)$ - вероятностная пространство.\\ 92 | $A \subset \Omega$, $P(A) = \sum_{w \in A} P(w)$. \\ 93 | \tu{Def}: $A, B$ - события, $P(B) > 0$. \tb{P(A|B)} - вероятность события A, если наступило событие B. Тогда $P(A|B) = \dfrac{\sum_{w \in A \cap B} P(w)}{\sum_{w \in B} P(w)} = \dfrac{P(A \cap B)}{P(B)}$. \\ 94 | \tu{Def}: A и B независимые, если P(A|B) = P(A). \\ 95 | Тогда, если A и B независимые, то $P(A \cap B) = P(A) \cdot P(B)$. \\ 96 | 97 | 98 | 99 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_02_2910.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Макоян Артем, ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Лекция по АиСД 29.10} 65 | 66 | \begin{document} 67 | 68 | $ \xi : \Omega \rightarrow \R $ - случайная величина. $ \xi(w) $ - значение, $ w \in \Omega $. \\ 69 | \tu{Пример:} Есть 5 марок автомобиля, их стоимости и их количества. 70 | A - 1000 - 100; B - 2000 - 5; C - 3000 - 5; D - 2000 - 20; E - 1500 - 30; 71 | Тогда нас интересуют $P(\xi = 1000) = \dfrac{100}{160}, P(\xi = 1500) = \dfrac{30}{160}, P(\xi = 2000) = \dfrac{25}{160}, P(\xi = 3000) = \dfrac{5}{160} $.\\ 72 | 73 | \tu{Матожидание} $E(\xi) = \sum_{w \in \Omega} \xi(w) \cdot P(w) = \sum_{x} x \cdot P(\xi = x) $. \\ 74 | 75 | \tu{Индикаторная случайная величина:} 76 | $I_A = 77 | \begin{cases} 78 | 1, w \in A \\ 79 | 0, w \notin A \\ 80 | \end{cases} 81 | $Тогда $E(I_A) = P(A)$. \\ 82 | 83 | Пусть есть 2 случайной величины $\xi_1$ и $\xi_2$. Тогда $E(\alpha \xi_1 + \beta \xi_2) = \alpha E(\xi_1) + \beta E(\xi_2)$.\\ 84 | $E(\alpha \xi_1 + \beta \xi_2) = \sum_{w \in \Omega}(\alpha \xi_1(w) \cdot P(w) + \beta \xi_2(w) \cdot P(w)) = \alpha \sum_{w \in \Omega} \xi_1(w) \cdot P(w) + \beta \sum_{w \in \Omega} \xi_2(w) \cdot P(w) = \alpha E(\xi_1) + \beta E(\xi_2)$ \\ 85 | 86 | Две случайные величины называются \tu{независимые}, если $ \forall x, y : P(\xi_1 = x $ и $ \xi_2 = y) = P(\xi_1 = x) \cdot P(\xi_2 = y) $. \\ 87 | $n$ случайных величин называются \tu{попарно независимыми}, если любые 2 величины независимы. \\ 88 | \ti{независимы в совокупности - см семинар} \\ 89 | 90 | $\xi_1$ и $\xi_2$ - случайные независимые величины. Тогда $E(\xi_1 \xi_2) = E(\xi_1)E(\xi_2)$. \\ 91 | $E(\xi_1 \xi_2) = \sum_{w \in \Omega} \xi_1(w) \xi_2(w) P(w) = \sum_{x} x \cdot P(\xi_1 \xi_2 = x) = \sum_{(u,v)} uv \cdot P(\xi_1 = u $ и $ \xi_2 = v) = [\xi_1 $ и $ \xi_2 $ независимы$] = \sum_{(u, v)} uv \cdot P(\xi_1 = u) \cdot P(\xi_2 = v) = (\sum_{u} u \cdot P(\xi_1 = u)) \cdot (\sum_{v} v \cdot P(\xi_2 = v)) = E(\xi_1)E(\xi_2)$. \\ 92 | 93 | \tu{Задача о назначениях}. Есть $n$ работников и $n$ работ. Есть таблица, где $a_{ij}$ - сколько i-ый работник берет за j-ую работу. Нужно распределить работников по работам так, чтобы суммарная плата за все работы была миниальна. \\ 94 | Оценим матожидание затрат при случайном решении. $A_{ij}$ - событие, когда i-ый работник делает j-ую работу. $\xi = \sum_{(i,j)} I_{A_{ij}} \cdot a_{ij}$. Тогда $E(\xi) = \sum_{(i,j)} E(I_{A_{ij}} = \sum_{(i,j)} a_{ij}P(A{ij}) = \sum_{(i,j)} a_{ij} \cdot \frac{1}{n} $. \\ 95 | 96 | \tu{Найти максимальный разрез в неориентированном невзвешанном графе}. \\ 97 | Будем строить случайный разрез(каждую вершину либо в $A$, либо в $\stackrel{-}{A}$). Тогда $\xi$ - величина нашего разреза. $\xi = \sum_{e \in E(G)} I_{B_{e}}$, где $B_e$ - событие, когда $e$ лежит в разрезе. $P(e \in $разрез$) = \frac{1}{2}$. Тогда $E(\xi) = E(\sum_{e \in E(G)} I_{B_E}) = \sum E(I) = \dfrac{1}{2} \abs{E(G)}$. \\ 98 | 99 | Есть перестановка $ p_1 \dots p_n$. Алгоритм жадно набирает возрастающую подпоследовательность. Какое матожидание длины этой подпоследовательности? \\ 100 | Событие $A_i$ - алгоритм возьмет $p_i$. $E(\xi) = E(\sum I_{A_i}) = \sum P(A_i) $. $P(A_i) = P(\forall j < i : p_j < p_i) = \frac{1}{i}$. Тогда $E(\xi) = \sum_{i = 1}^n \frac{1}{i} = \Theta(log n)$. \\ 101 | 102 | \tu{Дисперсия} $D(\xi) = \sum_{w \in \Omega} P(w)(\xi(w) - E(\xi))^2$.\\ 103 | Свойства: 104 | 105 | \begin{itemize} 106 | \item $D(\xi_1 + \xi_2) = D(\xi_1) + D(\xi_2)$, $\xi_1$ и $\xi_2$ независимы \\ 107 | \item $D(\lambda \xi_1) = \lambda^2 D(\xi_1) $ \\ 108 | \end{itemize} 109 | 110 | \tu{Неравенство Маркова}. $\xi : \Omega \rightarrow \R_+$. $P(\xi(w) \geq E(\xi) \cdot k) \leq \dfrac{1}{k} $. \\ 111 | 112 | \tu{Неравенство Чебышева}. $\xi : \Omega \rightarrow \R$. $P(\abs{\xi - E(\xi)} \leq \alpha) \leq \dfrac{D(\xi)}{\alpha^2}$. 113 | 114 | 115 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_03_0511.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Лекция по АиСД 05.11} 65 | 66 | \begin{document} 67 | 68 | 69 | \textbf{Модели} 70 | 71 | RAM-модель (Random Access Machine) 72 | Вопросы, возникающие при создании модели 73 | \begin{enumerate} 74 | \item адресация 75 | \item какие инструкции 76 | \item рекурсия 77 | \item где лежат инструкции 78 | \item размер данных 79 | \item кол-во памяти 80 | \item случайность 81 | \end{enumerate} 82 | 83 | \paragraph{Адресация} 84 | 85 | Есть ячейки, в которых можно хранить целые числа (ограничения на $MAXC$ разумные, и на них введена неявная адресация 86 | 87 | \textit{Замечание.} Явная адресация --- при создании элемента получаем адрес и можем пользоваться только этим адресом. Неявно --- можем получать адреса каким-то своим образом, к примеру, $ptr + 20$. 88 | 89 | \paragraph{Кол-во памяти} 90 | 91 | Неявное соглашение RAM --- время работы не меньше памяти. По дефолту считаем, что мы его инициализируем мусором 92 | 93 | \paragraph{Где инструкции} 94 | 95 | Хранить инструкции можно в памяти и где-то снаружи. Мы будем хранить снаружи (внутри --- RASP-модель). Иначе говоря, инструкции и данные отделены. 96 | 97 | 98 | \paragraph{Какие инструкции} 99 | В нашей модели есть инструкции следующих типов: 100 | 101 | \begin{itemize} 102 | \item работа с памятью 103 | \item ветвление 104 | \item передача управления (=$goto$), 105 | \item арифметика (at least $a + b, a - b, \frac{a}{b}, \cdot, mod, \lfloor \frac{a}{b} \rfloor$) 106 | \item сревнения (at least $a < b, a > b, a \le b, a \ge b, a = b, a \neq b$) 107 | \item логические (at least $\land, \lor, \oplus, \lnot$) 108 | \item битовые операции ($>>, <<, \&, |, \sim, \oplus$) 109 | \item математические функции (опять-таки, в рамках разумного) 110 | \item rand 111 | \end{itemize} 112 | 113 | Все инструкции работают от конечного разумного числа операндов (не умеем в векторные операции) 114 | 115 | \paragraph{Размер данных} 116 | 117 | $\exists~C, k~:~ C \cdot A^k \cdot n^k$ --- верхнее ограничение на величины промежуточных вычислений. 118 | 119 | \paragraph{Рекурсия} 120 | 121 | Рекурсия всегда линейна по памяити относительно глубины. 122 | 123 | \paragraph{Случайность} 124 | 125 | Мы считаем, что у нас есть абсолютно рандомная функция. Будем полагать, что у нас есть источник энтропии, выдающий случайности в промежутке $[0, 1]$. 126 | 127 | \textbf{Время работы.} \begin{itemize} 128 | \item наихудшее --- $t = \displaystyle\max_{input, random} t(input, random)$ 129 | \item наилучшее --- $t = \displaystyle\max_{input} \displaystyle\min_{random} t(input, random)$ 130 | \item ожидаемое --- $E\ t = \displaystyle\max_{input} {Average}_{random} t(input, random)$ 131 | \item на случайных данных --- $t = Average_{input} Average_{random} t(input, random)$ 132 | \end{itemize} 133 | 134 | 135 | \textbf{Алгоритмы} 136 | 137 | Методы доказательства корректности алгоритма. 138 | \begin{enumerate} 139 | \item индукция 140 | \item инвариант 141 | \item от противного 142 | \end{enumerate} 143 | 144 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_04_1211.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | 14 | \title{Title} 15 | \author{Амеличев Константин, ПМИ 191.} 16 | \date{Date} 17 | 18 | \newcommand{\problem}[2]{ 19 | 20 | \section {Задача #1} 21 | \textbf {Постановка задачи.} {#2} 22 | 23 | \textbf {Решение.} 24 | } 25 | 26 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 27 | 28 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 29 | 30 | \newcommand{\mintedparams}{ 31 | % frame=lines 32 | % framesep=2mm, 33 | % baselinestretch=1.2, 34 | % bgcolor=LightGray 35 | } 36 | 37 | \pagestyle{fancy} 38 | \fancyhf{} 39 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 40 | \fancyhead[RE,LO]{Лекция по АиСД 12.11} 41 | 42 | \begin{document} 43 | 44 | Способы оценки времени работы: 45 | \begin{itemize} 46 | \item Прямой учет 47 | 48 | \item Рекурсивная оценка 49 | 50 | \item Амортизационный анализ 51 | \end{itemize} 52 | 53 | \paragraph{Прямой учет} 54 | 55 | Время работы строчки --- произведение верхних оценок по всем строчкам-предкам нашей. 56 | 57 | К примеру 58 | 59 | \begin{minted}{c++} 60 | while (!is_sorted()) { // O(# inversions) = O(n^2) 61 | for (int i = 0; i + 1 < n; i++) { // O(n) * O(parent) = O(n^3) 62 | if (a[i] > a[i + 1]) { 63 | swap(a[i], a[i + 1]); // O(n^3) 64 | } 65 | } 66 | } 67 | \end{minted} 68 | 69 | \paragraph{Рекурсивная оценка} 70 | 71 | Пример --- сортировка слиянием 72 | 73 | Нас интересует две вещи: инвариант и переход. Для оценки времени используем рекурренту вида $T(n) = O(f(n)) + \rangesum{n' \in calls}{} T(n')$ 74 | 75 | При этом если мы доказываем время работы, то показываем $T(n) \le c \cdot f(n)$, зная, что для $n'\ \exists c:\ T(n') \le c \cdot f(n)$ 76 | 77 | Важно, что $c$ глобальное и не должно увеличиваться в ходе доказательства 78 | 79 | 80 | \paragraph{stable sort} 81 | Делает сортировку, не меняя порядок равных элементов относительно исходной последовательности. Merge-sort стабилен. 82 | \paragraph{inplace-algorithm} 83 | Не требует дополнительной памяти и делает все прямо на данной памяти (у нас есть $\log n$ памяти на рекурсию). Quick-sort inplace. 84 | 85 | \paragraph{Время работы qsort} 86 | 87 | $$T(n) = \max_{input} average_{rand} t(input, rand) = \max_{|input|=n} E t(input)$$ 88 | 89 | $$T(n) \le \Theta(n) + \frac{1}{n} \rangesum{k=0}{n-1} (T(k + 1) + T(n - k)) \le \Theta(n) + \frac{2}{n} \cdot \rangesum{k=1}{n} T(k - 1) \le a \cdot n + \frac{2}{n} \rangesum{k=1}{n} c \cdot (k - 1) \cdot \log (k - 1) \le$$ 90 | 91 | $$\le a \cdot n + \frac{2}{n} \rangesum{k=1}{\frac{n}{2}} c \cdot (k - 1) \cdot \log n - \frac{2}{n} \rangesum{k=1}{\frac{n}{2}} c \cdot (k - 1) + \frac{2}{n} \rangesum{k=\frac{n}{2} + 1}{n} c \cdot (k - 1) \cdot \log n \le$$ 92 | 93 | $$\le a \cdot n + \frac{2}{n} \cdot n^2 \cdot \log n - \frac{2c}{n} \cdot \frac{(n - 2)^2}{4} \le a \cdot n + cn \log n - \frac{c (n - 2)}{4} \le cn \log n$$ 94 | 95 | $$\frac{c (n - 2)}{4} \ge a \cdot n$$ 96 | 97 | $$c \cdot n - 2c \ge 4 \cdot a \cdot n$$ 98 | 99 | $$c \ge \frac{4 \cdot a \cdot n}{(n - 2)}$$, что верно для достаточно больших $n$. 100 | 101 | \paragraph{Ограничение на число сравнений в сортировке} 102 | 103 | Бинарные сравнения на меньше. 104 | 105 | Рассмотрим дерево переходов. Для перестановки есть хотя бы один лист --- листьев котя бы $n!$ 106 | 107 | $$L(T) \le 2^x, d(T) \le x$$, если $x$ --- ответ 108 | 109 | 110 | $$L(T) \ge n!$$ 111 | 112 | $$d(T) \ge \log n! \ge \log{\frac{n}{2}}^{\frac{n}{2}} = \log 2^{(\log \frac{n}{2}) \cdot \frac{n}{2}} = \frac{n}{2} \cdot \log \frac{n}{2} = \Omega (n \log n)$$ 113 | 114 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_05_1411.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | \pagestyle{fancy} 38 | \fancyhf{} 39 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 40 | \fancyhead[RE,LO]{Алгоритмы 14.11} 41 | 42 | \begin{document} 43 | 44 | \section{Сортировки основанные на внутреннем виде данных} 45 | 46 | Имеем $n$ чисел $[0, U - 1],\ U = 2^w$, числа укладываются в RAM-модель 47 | 48 | \paragraph{Сортировка подсчетом} 49 | 50 | Заводим массив $cnt[U],\ cnt[x] = |\{i : a_i = x\}|$. Дальше переводим $count \rightarrow pref,\ pref[x] = pref[x - 1] + count[x]$ 51 | 52 | $O(n + U)$ 53 | 54 | \paragraph{Поразрядная сортировка} 55 | 56 | $b_{ij}$---$j$-й бит $i$-го числа. (Сортируем бинарные строки длины $w$) 57 | 58 | Поочередно сортируем строки, разбивая их на классы эквивалентности по $iter$ последним символам. После чего мы стабильно сортируем по $(iter+1)$-му символу. 59 | 60 | $O(n \log U)$ 61 | 62 | \paragraph{Bucket sort} 63 | 64 | Разбиваем множество на корзины, каждой корзине соответствует отрезок. В каждой корзине запускаемся рекурсивно. 65 | 66 | $O(n \log U)$ 67 | 68 | В продакшне используют первую пару итераций, чтобы сильно снизить размерность на реальных данных. 69 | 70 | Пусть мы хотим отсортить равновероятные числа из $[0, 1]$. В каждом бакете отсортируем за квадрат. Получим $O(n)$. 71 | 72 | $$t(n) \le \rangesum{i=1}{n} c \cdot (1 + E (cnt_i)^2) \le c \cdot n + c \cdot \rangesum{i=1}{n} E (cnt_i^2) = $$ 73 | $$ = c \cdot n + c \cdot \rangesum{i=1}{n} \rangesum{j=1}{n} E I_{A_{ij}} = c \cdot n + c \cdot n^2 \cdot \frac{1}{n} \le 2 \cdot c \cdot n$$ 74 | 75 | \section{Иерархия памяти} 76 | 77 | Нас интересует задержка (latency), пропускная способность (throughput). Подгрузка $x$ данных занимает $l + \frac{x}{t}$ 78 | 79 | От долгой к быстрой 80 | \begin{enumerate} 81 | \item external machine / internet 82 | \item HDD 83 | \item SSD 84 | \item RAM 85 | \item L3 86 | \item L2 87 | \item L1 88 | \item registers 89 | \end{enumerate} 90 | 91 | \section{Алгоритмы во внешней памяти} 92 | 93 | $n$ --- размер задачи 94 | 95 | $M$ --- размер $RAM$ 96 | 97 | $B$ --- блок данных 98 | 99 | $B \ll M \ll n$ 100 | 101 | $\log n \ll B$ 102 | 103 | $B < \sqrt{M}$ (но это неявно и не факт) 104 | 105 | \paragraph{Mergesort во внешней памяти} 106 | 107 | Обычный mergesort, но три типа событий в $merge$: 108 | \begin{enumerate} 109 | \item Кончился первый буфер --- подгружаем новый 110 | \item Кончился второй --- аналогично 111 | \item Кончился буфер для слияния --- выписываем обратно в RAM и сбрасываем 112 | \end{enumerate} 113 | 114 | $O(\frac{n}{B} \log n) \rightarrow O(\frac{n}{B} \log {\frac{n}{B}}) \rightarrow O(\frac{n}{B} \log_{\frac{M}{B}} {\frac{n}{B}})$ 115 | 116 | +2 идеи: \begin{enumerate} 117 | \item Дошли до размера $M$ --- явно посортим в RAM 118 | \item Можем сливать сразу $\frac{M}{B}$ массивов 119 | \end{enumerate} 120 | 121 | \end{document} 122 | -------------------------------------------------------------------------------- /tex_files/lec_06_1911.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 19.11} 42 | 43 | \begin{document} 44 | 45 | \section{Простые структуры данных} 46 | 47 | \paragraph{Требования к структуре данных:} 48 | \begin{itemize} 49 | \item От СД мы хотим обработку каких-то наших запросов. 50 | \item online-offline. Бывает, что мы знаем все запросы, бывает, что мы узнаем запрос только тогда, когда отвечаем на предыдущий 51 | \item При обсуждении времени работы отделяется время на препроцессинг и на последующие ответы на запросы (query). 52 | \end{itemize} 53 | 54 | \subsection {Data structure / interface} 55 | \hspace{\fill} 56 | \textit{Структура данных} --- это какой-то математический объект, который умеет отвечать на наши запросы конкретным способом. Красно-черное дерево --- это структура данных. 57 | \\ 58 | \textit{Интерфейс} --- это объект, с которым может взаимодействовать пользователь, который каким-то образом умеет отвечать на наши запросы (пользователю все равно, как, его волнует только то, что интерфейс реализует, и за какое время(память) он это делает). $std::set$ --- это интерфейс. 59 | \\ 60 | \textit{Итератор} --- это специальный объект, отвечающий непосредственно за ячейку в структуре данных. Для того, чтобы удалить элемент, мы должны иметь итератор на этот элемент. Т.е. удаление по ключу работает за $O(erase)$, а удаление по значению за $O(find) + O(erase)$ 61 | 62 | \paragraph{list} 63 | Списки бывают двусвязными, односвязными, циклическими. У каждого элемента есть ссылка на следующий (и иногда на предыдущий), а также есть отдельный глобальный указатель на начало списка. 64 | 65 | 66 | \paragraph{stack} 67 | Стек --- структура данных, которая умеет делать добавление в конец, удаление из конца, взятие последнего элемента, за $O(1)$. 68 | 69 | \paragraph{queue} 70 | Очередь --- структура данных, которая умеет делать добавление в конец, удаление из начала, взятие первого элемента, за $O(1)$. 71 | 72 | \paragraph{deque} 73 | Двусторонняя очередь --- структура данных, которая умеет делать добавление, удаление и взятие элемента с любого конца последовательности, за $O(1)$. 74 | 75 | \paragraph{priority\_queue} 76 | Очередь с приоритетами ака куча --- структура данных, которая умеет делать добавление, удаление, и быстрые операции с минимумом, представляющая из себя дерево с условием $parent(u) = v \rightarrow value(v) \le value(u)$. 77 | 78 | 79 | Все эти структуры реализуются как на массиве (храним последовательную память и указатели на начало/конец), так и на списках (что на самом деле является тем же самым, что и на массиве, просто ссылка вперед эквивалентна $a_i \rightarrow a_{i + 1}$ в терминологии массивов, \textit{прим. автора}). 80 | 81 | Структура данных на массиве кратно быстрее аналогичной на ссылках, потому что массив проходится по кэшу и не требует дополнительной памяти. 82 | 83 | \begin{center} 84 | \begin{tabular}{c c c c c c c c c} 85 | data structure & add & delete & pop & find & top & build & min & get by index\\ 86 | stack & $O(1)$ & - & $O(1)$ & - & $O(1)$ & $O(n)$ & $O(n)$ & -\\ 87 | dynamic array & $O(1)$ & $O(n)$ & $O(1)$ & $O(n)$ & $O(1)$ & $O(n)$ & $O(n)$ & $O(1)$ \\ 88 | queue & $O(1)$ & - & $O(1)$ & - & $O(1)$ & $O(n)$ & $O(n)$ & -\\ 89 | deque & $O(1)$ & - & $O(1)$ & - & $O(1)$ & $O(n)$ & $O(n)$ & $O(1)$\\ 90 | linked list & $O(1)$ & $O(1)$ & $O(1)$ & $O(n)$ & $O(1)$ & $O(n)$ & $O(n)$ & $O(n)$\\ 91 | sorted array& $O(n)$ & $O(n)$ & $O(1)$ & $O(\log n)$ & $O(1)$ & $O(n \log n)$ & $O(1)$ & $O(1)$ \\ 92 | priority\_queue& $O(\log n)$ & $O(\log n)$ & $O(\log n)$ & $O(1)$ & $O(n)$ & $O(1)$ & - 93 | \end{tabular} 94 | \end{center} 95 | 96 | \subsection{Двоичная куча} 97 | 98 | Реализация двоичной кучи на массиве --- создаем массив размера $sz$, и создаем ребра $i \rightarrow 2 \cdot i,\ i \rightarrow 2 \cdot i + 1$. 99 | 100 | От такой кучи мы хотим: 101 | \begin{itemize} 102 | \item insert(x) 103 | \item get\_min() 104 | \item extract\_min() 105 | \item erase 106 | \item change = \{decrease\_key, increase\_key\} 107 | \end{itemize} 108 | 109 | Для такой кучи мы реализуем $sift\_up(x),\ sift\_down(x)$ --- просеивание вниз и вверх. Процедура должна устранить конфликты с элементом $x$. Остальные операции умеют реализовываться через нее. 110 | 111 | $$insert = add\_leaf + sift_up$$ 112 | 113 | $$extract\_min = swap(root, last) + last -= 1 + sift_down(root)$$ 114 | 115 | $$erase = decrease\_key(-\infty) + extract\_min$$ 116 | 117 | Отдельно отметим построение кучи за $O(n)$ --- sift\_down поочередно для всех элементов $n,~n~-~1,~\dots,~1$. 118 | 119 | \begin{minted}{c++} 120 | void sift_up(int v) { // v >> 1 <=> v / 2 121 | if (key[v] < key[v >> 1]) { 122 | swap(key[v], key[v >> 1]); 123 | sift_up(v >> 1); 124 | } 125 | } 126 | \end{minted} 127 | 128 | \begin{minted}{c++} 129 | void sift_down(int v, int size) { // indexes [1, size] 130 | if (2 * v > size) { 131 | return; 132 | } 133 | int left = 2 * v; 134 | int right = 2 * v + 1; 135 | int argmin = v; 136 | if (key[v] > key[left]) { 137 | argmin = left; 138 | } 139 | if (right <= size && key[right] < key[argmin]) { 140 | argmin = right; 141 | } 142 | if (argmin == v) { 143 | return; 144 | } 145 | swap(key[v], key[argmin]); 146 | sift_down(argmin, size); 147 | } 148 | \end{minted} 149 | 150 | \end{document} 151 | -------------------------------------------------------------------------------- /tex_files/lec_07_2611.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 26.11} 42 | 43 | \begin{document} 44 | 45 | \textit{Какое-то сегодняшнее дополнение про бинарную кучу есть в прошлом конспекте} 46 | \paragraph{K-чная куча} 47 | 48 | Куча на полном K-чном дереве. Эту кучу можно так же хранить в массиве, с 0-индексацией. 49 | \begin{itemize} 50 | \item $sift\_up$ такой же, $O(\log_k n)$ 51 | \item $sift\_down$ ищет минимум среди $k$ элементов на каждом шаге, поэтому работает за $O(k \cdot \log_k n)$. 52 | \end{itemize} 53 | 54 | \begin{tabular}{c|c|c} 55 | & $2-heap$ & $k-heap$ \\ 56 | \hline 57 | $insert$ & $O(\log n)$ & $O(\log_k n)$ \\ 58 | \hline 59 | $extract\_min$ & $O(\log n)$ & $O(k \log_k n)$ \\ 60 | \hline 61 | $decrease key$ & $O(\log n)$ & $O(\log_k n)$ \\ 62 | \hline 63 | $increase key$ & $O(\log n)$ & $O(k \log_k n)$ \\ 64 | \hline 65 | \end{tabular} 66 | 67 | \paragraph{Дейкстра на $K$-ной куче} 68 | 69 | Алгоритм Дейкстры достает минимум $n$ раз, и улучшает ключ $m$ раз 70 | 71 | $$ a \cdot \log_k n = b \cdot k \cdot \log_k n, a = m, b = n$$ 72 | 73 | Отсюда $k = \frac{a}{b} = \frac{m}{n}$ в случае Дейкстры. Еще отметим, что $k \ge 2$. 74 | 75 | В случае когда $a = b^q,\ q > 1$, то $k$-куча структура работает за $O(1)$ (вроде бы этот факт мы докажем в домашке), причем с хорошей константой, поэтому применимо на практике (привет, фибоначчиева куча!). 76 | 77 | \paragraph{Амортизационный анализ} 78 | 79 | Идея в том, что мы хотим оценить суммарное число операций, а не на каждом шаге работы. То есть вполне может быть итерация алгоритма за $O(n)$, но нам важно, что суммарное число $O(n \log n)$ 80 | 81 | Так что есть $t_{real} = t,\ t_{amortized} = \tilde t$. 82 | 83 | \paragraph{Метод кредитов} 84 | 85 | Элементам структуры сопоставляем сколько-то монет. Этими монетами элемент <<расплачивается>> за операции. Также мы накидываем сколько-то монет на операцию. Запрещаем отрицательное число монет. Начинаем с нулем везде. 86 | 87 | Обозначим состояния структуры за $S_0, S_1, \dots, S_n$. Каждый переход стоил $t_i$, $t_i \ge |operations|$, Где $t_i$ --- это сколько мы потратили. Также на $i$-м шаге мы вбрасываем в систему $\tilde t_i$ монет. Тогда $$\sum t_i \le \sum \tilde t_i \le A \rightarrow O(A)$$ 88 | 89 | \paragraph{Стек с минимумом} 90 | 91 | \begin{itemize} 92 | \item $min\_stack$ 93 | \item push 94 | \item pop 95 | \item $get\_min$ 96 | \end{itemize} 97 | 98 | $m_i = \min (m_{i-1}, a_i)$ --- поддерживаем минимумы. Операции тривиальны 99 | 100 | \paragraph{Очередь с минимумом на двух стеках} 101 | 102 | Храним два стека с минимумом, один из которых мысленно наращиваем в одну сторону, а другой в другую, при этом очередь выглядит как бы как склеенные стеки. То есть мы добавляем элемент в первый стек, а извлекать хотим из второго. 103 | 104 | $$X \rightarrow a_n, a_{n - 1}, \dots, a_1,\ |\ , b_1, b_2, \dots, b_n \rightarrow Y$$ 105 | 106 | Тогда единственная сложная операция --- если мы хотим извлечь минимум, а второй стек пустой. Тогда мы все элементы из первого перекинем во второй по очереди с помощью <<извлеки-добавь>> 107 | 108 | Почему это работает за $O(1)$ на операцию амортизированно? Представим каждому элементу при рождении 2 монеты, одну из которых мы потратим на добавление в первый стек, а вторую на удаление через второй. 109 | 110 | \paragraph{set для бедных} 111 | 112 | Хотим не делать $erase$, только $insert$, $find$, $get\_min$. Храним $\log n$ массивов, $|a_i| = 2^i$, каждый из которых по инварианту будет отсортирован. Тогда $get\_min$ рабтает за $O(\log n)$ --- просто берем минимум по всем массивам. Аналогично $find$ делается бинпоисками за $O(\log^2 n)$ 113 | 114 | А как добавлять за $\tilde O(\log n)$? Каждый элемент при добавлении в структуру получает $\log n$ монет. Когда мы добавляем элемент, мы создаем новый массив ранга 0. Если было два массива ранга 0, сольем их в новый массив ранга 1 за суммарный размер (и заберем монетку у всех элементов во время слияния), и так далее, пока не создадим уникальный массив для текущего ранга. 115 | 116 | \paragraph{Метод потенциалов} 117 | 118 | $\Phi(S_i)$ --- потенциал, который зависит только от состояния структуры (\textbf{не от} последовательности действий, которая к такому состоянию привела). 119 | 120 | Опять вводим $t_i$, $\sum t_i = O(f(n))$. Определим амортизированное время работы: 121 | 122 | $$\tilde t_i = t_i + (\Phi(S_{i+1}) - \Phi(S_i))$$ 123 | 124 | $$t_i = \tilde t_i + \Phi(S_i) - \Phi(S_{i+1})$$ 125 | 126 | Пусть мы показали $\tilde t_i \le f(n)$. Тогда 127 | 128 | $$\sum t_i \le n \cdot f(n) + \Phi(0) - \Phi(n)$$ 129 | 130 | Нормальный потенциал --- такой, что из неравенства выше все еще можно показать О-оценку на $\sum t_i = O(n \cdot f(n))$. 131 | 132 | \paragraph{deque для богатых} 133 | 134 | Хотим deque с поддержкой минимума. 135 | 136 | Храним два стека как для обычной очереди. Все операции хорошо работают как на очереди, кроме перестройки структуры. В случае с очередью надо было переливать стеки только в одну сторону, а теперь иногда нужно туда-сюда. 137 | 138 | Теперь мы будем перекидывать только половину элементов. Тогда нам понадобитсяя 3 стека, один из которых будет вспомогательным для перестройки (там иначе стеки развернуты). 139 | 140 | $\Phi(S_i) = |Size_1 - Size_2|$ 141 | 142 | 143 | 144 | \end{document} 145 | -------------------------------------------------------------------------------- /tex_files/lec_08_2711.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Макоян Артем, ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Лекция по АиСД 28.11} 65 | 66 | \begin{document} 67 | 68 | \tu{Куча}: insert, extract\_min, decrease\_min, decrease\_key, increase\_key, merge. Хотим добавить операцию merge - объединить 2 кучи. Считаем, что можем делать операции амортизировано (не разделяем кучи и кучи не персистентные). Меньшую кучу будем добавлять в большую ("переливать" в большую). 69 | 70 | Хотелось бы раздать каждой вершине по $\log n$ монет и говорить, что, когда мы "переливаем" кучу, все элементы этой кучи платят по монете. Тогда монет хватит, так как при каждом переливании размер кучи, где находится вершина увеличивается вдвое, значит каждая вершина перельется не более $\log n$ раз. Но все ломается из-за того, что мы можем удалять вершины. Можно ввести потенциалы (подумать), а можно сказать, что у каждого элемента есть ранг (r(i)) и при каждом переливании все ранги меньшей кучи увеличиваются на 1. Тогда амортизировано merge будет работать за O($\log^2 n$). \\ 71 | 72 | \tu{Биномиальная куча}: \\ 73 | 74 | Вершин в биномиальной кучи $2^n$, на $k$-ом слое $C_n^k$ вершин. Из каждой вершины храним ребро в старшего сына, в предка и в следующего брата. $B_k = $ merge$(B_{k-1}, B_{k-1})$. %вставить картинку 75 | Заметим, что merge деревьев одного ранга работает за O(1). \\ 76 | 77 | \includegraphics[width=15cm]{pictures/binominial_heap_add.png} 78 | 79 | 80 | Если у нас есть n чисел, то как мы их поместим в кучу размера $2^k$? $n = 2^{k_1} + 2^{k_2} \dots + 2^{k_m}$. Тогда можем хранить все элементы как кучи рангов $k_1, \dots k_m$. Тогда при merge нужно объединять два списка биномиальных куч (будем делать это 2 указателями по 2 массивам), будем объединять кучи одинаковых рангов \\ %вставить картинку или объяснение 81 | 82 | insert - создаем кучу ранга 0 с нашим элементом и делаем merge за $O(\log n$). 83 | 84 | Для поиска минимума будем просто поддерживать глобальный минимум, изменяя его за O($\log n$) (пробегаясь по всем кучам) при каждом запросе изменения. \\ 85 | 86 | decrease\_key \\ 87 | 88 | extract\_min \\ 89 | 90 | increase\_key: decrease\_key(v, $-\infty$) $\to$ extract\_min $\to$ insert(x). Работает за O($\log n$). \\ 91 | 92 | \includegraphics[width=15cm]{pictures/binominial_heap.png} 93 | 94 | \tu{Фибоначчиева куча}: (чет я устал техать, чекайте у Кости) 95 | 96 | \begin{center} 97 | \begin{tabular}{|c|c|c|c|} 98 | \hline 99 | Операции & binary heap & binomial heap & fibonacci heap \\ 100 | \hline 101 | insert & O($\log n$) & O($\log n$) & O(1) \\ 102 | extract\_min & O($\log n$) & O($\log n$) & $\tilde{O}(\log n)$ \\ 103 | decrease\_min & O($\log n$) & O($\log n$) & $\tilde{O}(1)$ \\ 104 | increase\_min & O($\log n$) & O($\log n$) & $\tilde{O}(\log n)$ \\ 105 | merge & $\tilde{O}(\log^2 n)$ & O($\log n$) & O(1) \\ 106 | get\_min & O(1) & O(1) & O(1) \\ 107 | \hline 108 | \end{tabular} 109 | \end{center} 110 | 111 | 112 | 113 | \end{document} 114 | -------------------------------------------------------------------------------- /tex_files/lec_08_2811.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 27.11} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Больше куч!} 46 | 47 | \begin{center} 48 | \begin{tabular}{c|c|c|c} 49 | &$binary heap$ & $binomial heap$ & $fibonacci heap$ \\ 50 | $insert$ & $O(\log n)$ & $O(\log n)$ & $O(1)$\\ 51 | $extract\_min$ & $O(\log n)$ & $O(\log n)$ & $\tilde O(\log n)$\\ 52 | $decrease\_key$ & $O(\log n)$ & $O(\log n)$ & $\tilde O(1)$\\ 53 | $increase\_key$ & $O(\log n)$ & $O(\log n)$ & $\tilde O(\log n)$\\ 54 | $merge$ & $\tilde O(\log^2 n)$ & $O(\log n)$& $O(1)$\\ 55 | $get\_min$ & $O(\log n)\ or\ O(1)$ & $O(1)$ 56 | \end{tabular} 57 | \end{center} 58 | 59 | \paragraph{Биномиальная куча} 60 | \hspace{\fill} 61 | 62 | Храним биномиальные деревья. Каждому дереву сопоставим ранг. Ранг дерева полностью определяет его структуру. Дерево ранга 0 --- одна вершина. Дерево ранга 1 --- одно ребро. В общем случае, дерево ранга $n$ содержит корень и полное двоичное дерево размера $2^{n-1}$. Дерево ранга $n+1$ --- это два слитых вместе дерева ранга $n$ --- корень второго указывает на корень первого, а корень первого теперь будет указывать на оба бинарных дерева. 63 | 64 | Биномиальная куча --- это набор из логарифма биномиальных куч. 65 | 66 | Слияние двух деревьев мы научились делать за $O(1)$ --- меньшая вершина по ключу становится новым корнем, а дальше перекидываем указатели. 67 | 68 | Слияние двух куч --- это алгоритм сложения двоичных чисел --- при сливании двух деревьев ранга $n$ мы <<переносим>> прибавление кучи ранга $n+1$ 69 | 70 | Как добавлять элемент? Создать кучу на 0 элементов и слить их вместе. 71 | 72 | Уменьшение ключа --- напишем $sift\_up$ на нашей новой куче 73 | 74 | Удаление минимума --- Заметим, что если в правом дереве пройти по правым детям и обозначим их за корни, а их левых детей за полные бинарные деревья, то мы получим набор деревьев рангов $0, 1, \dots, n - 1$. Обозначим их за новую кучу, и сольем все вместе. 75 | 76 | Увеличение ключа --- удалим соответствующий элемент и добавим другой. 77 | 78 | \includegraphics{pictures/binoial_heap.png} 79 | \newpage 80 | \paragraph{Фибоначчиева куча} 81 | \hspace{\fill} 82 | 83 | Хотим сделать биномиальную кучу с послаблаблениями --- делать операции в самый последний момент, менее четкую структуру, etc 84 | 85 | Есть деревья, их корни храним в двусвязном закольцованном списке. 86 | 87 | Всех детей для всех вершин храним в двусвязном закольцованном списке. 88 | 89 | Новый ранг --- это количество вершин в списке детей. 90 | 91 | На каждом дереве выполнена куча, а также поддерживаем глобальный минимум. 92 | 93 | Улучшение ключа делается так --- удаляем вершину из своего списка, вместе с поддеревом. Добавляем в корневой список. Если мы удалили уже вторую вершину в поддереве родителя, то делаем каскадное вырезание --- прыгаем по предкам с $mark = 1$, и вырезаем их в корневой список, причем все вырезания делаются по очереди. 94 | 95 | Удаление делается так --- мы приписываем всех детей к корневому списку, а потом вызываем $compact$, которая должна спасти наше дерево и навести порядок. 96 | 97 | Псевдокод тупых операций: 98 | \begin{minted}{c++} 99 | struct Node{ 100 | Node *child; 101 | Node *left; 102 | Node *right; 103 | Node *parent; 104 | int rank; 105 | bool mark; 106 | int value; 107 | } 108 | 109 | list roots; 110 | 111 | void insert(int x) { 112 | Node *node = new Node(x); 113 | roots.insert(node); 114 | } 115 | 116 | void merge(list a, list b) { 117 | merge(a, b); // O(1) haha super easy 118 | } 119 | 120 | int getmin() { 121 | return argmin->value; 122 | } 123 | \end{minted} 124 | 125 | \paragraph{compact} 126 | \begin{itemize} 127 | \item Сбрасываем пометки корневого списка в 0 128 | \item Переводим дерево в состояние, где все ранги разлиичны 129 | \item Храним ранги, мерджим одинаковые 130 | \item Как мерджим? Берем меньший корень, и записываем в его детей второй корень 131 | \end{itemize} 132 | 133 | Обозначим $R = \max rank$, $t(H) = root\ list\ size$, $m(H) = \sum_{v} mark(v)$ 134 | 135 | $compact$ работает за $O(R + t(H))$. 136 | 137 | \paragraph{Анализ времени работы} 138 | 139 | $extract\_min\ \& increase\_key$ --- $\tilde O(R)$. 140 | 141 | $\Phi(H) = t(H) + 2m(H) < 3n$ 142 | 143 | Пусть каскадное вырезание сделало $t_i $ действий. $m:\ 1 \rightarrow 0,\ t:\ +1$. Тогда $\Phi'(H) = \Phi(H) - 1$ за каждое вырезание. 144 | Тогда амортизированно вырезание работает за $O(1)$. 145 | 146 | Compact: 147 | 148 | $t(H) \le R$, $t'(H) = t(H) - R$ 149 | 150 | Амортизациованно работает за $2R + 1$ 151 | 152 | Хотим показать $R = O(\log n)$. 153 | 154 | $$\forall\ v \in H\ sz(v) \ge A^{rank(v)},\ A > 1$$ 155 | 156 | Тогда 157 | 158 | $$r(v) \le \log_A s(v) \le c \log n$$ 159 | 160 | Возьмем 161 | 162 | $$s(v) \ge \phi^{rank(v) - 2}$$ 163 | 164 | \textit{<Оффтоп про числа Фибоначчи>} 165 | \begin{enumerate} 166 | \item $F_n = F_{n - 1} + F_{n - 2},\ F_0 = F_1 = 1$ 167 | \item $F_n \ge \phi^{n - 2}$ 168 | \item $\forall\ i \ge 2:\ F_i = \rangesum{j=0}{i-2}F_j + 1$ 169 | \end{enumerate} 170 | \textit{} 171 | 172 | Почему инвариант на размеры сохраняется? Возьмем вершину $v$ с $k$ детьми. Рассмотрим детей в том порядке, в котором их склеивал компакт. Тогда на момент добавления $i$-й вершины в структуру, ее ранг совпадал с рангом $v$. Тогда из условия на удаление не более чем одного сына ($mark$) следует, что $rank(i) \ge i - 1$. Тогда мы доказываем по индукции, что у нас все размеры --- хотя бы числа фибоначчи, соответствующие рангу. Тогда $s(v) = \sum_{u \in g(v)} s(u) + 1 \ge \sum_{u \in g(v)} F_rank(u) + 1 \ge \rangesum{i=0}{rank(v) - 2}F_{i} + 1 \ge F_{rank(v) - 2}$ 173 | 174 | 175 | 176 | \end{document} 177 | -------------------------------------------------------------------------------- /tex_files/lec_09_0312.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 03.12} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Хэширование} 46 | 47 | Есть задача сравнения объектов: 48 | 49 | $$U = \{objects\},\ u, v \in U:\ u \neq v?$$ 50 | 51 | Введем функцию $h:\ U \rightarrow \mathbb{Z}_m$, такую что $\forall\ u, v \in U:\ u \sim v \rightarrow h(v) = h(u)$. Обычно $m \ll |U|$. 52 | 53 | Зачем юзать хэши, а не наивное сравнение? 54 | \begin{itemize} 55 | \item Бывает много сравнений, и мы не хотим дублировать вычисления 56 | \item Безопасность 57 | \item Для некоторых хешей верно, что $h(f(v, u)) = g(h(v), h(u))$. То есть можно вычислить хэш от некоего объекта, пользуясь уже посчитанными хэшами для других объектов. 58 | \item Иногда мы сравниваем объекты не на равенство, а на изоморфность. 59 | \item Сравнивать объекты бывает дорого 60 | \end{itemize} 61 | 62 | Требования к хэшу: 63 | \begin{itemize} 64 | \item вычислим за линейное время 65 | \item детерменирован 66 | \item семейство хэш-функций $\mathbb{H}$ (и можем взять сколько угодно оттуда) 67 | \item равномерность $\forall_{v \neq u} v,\ u:\ p_{h \in \mathbb{H}}(h(u) = h(v)) \simeq \frac{1}{m}$ 68 | \item масштабируемость 69 | \item необратимость 70 | \item (\textit{optional}) лавинный эффект (при маленьком изменении объекта хэш меняется сильно) 71 | \end{itemize} 72 | 73 | Важно, что мы хотим брать случайную функцию из семейства $\mathbb{H}$ на момент старта программы, потому что псевдослучайная функция на самом деле нам дает детерменированный алгоритм, который неверен. 74 | 75 | \paragraph{Идеальная хэш-функция} 76 | 77 | Так как объектов счетно, то отсортируем их, далее для каждого объекта запомним случайную величину от 1 до $m$ (или даже можем запоминать ее лениво!). 78 | 79 | \paragraph{Полиномиальный хэш} 80 | 81 | Сводим объекты к строкам и хэшируем строки: 82 | 83 | $$s = c_0c_2c_3 \dots c_{n-1},\ c_i > 0$$ 84 | 85 | $$h_b(s) = \rangesum{i=0}{n-1} c_i \cdot b^i\ (mod\ m)$$ 86 | 87 | $$p_b(h_b(s_1) = h_b(s_2)) \le \frac{n}{m}\ \text{для фиксированного m}$$ 88 | 89 | Доказательство: Рассмотрим функцию как многочлен, теперь для равных функций смотрим на то, равна ли разность многочленов нулю для какого-то $b$. У многочлена от $b$ степень равна $n$, а вероятность попасть в конкретный модуль $\frac{1}{m}$. 90 | 91 | $$h(s_1 + s_2) = h(s_1) + h(s_2) \cdot b^{|s_1|}$$ 92 | 93 | \end{document} 94 | -------------------------------------------------------------------------------- /tex_files/lec_10_1012.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 10.12} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Хэш-таблица} 46 | \hspace{\fill} 47 | 48 | Key-value storage: три типа операций~--- $set(x, y)$, $get(x)$, $has(x)$. Хэш-таблица умеет выполнять такие запросы за $O(1)$. 49 | 50 | Хотим делать индексацию не по ключу, а по хэшу от ключа $x_0 \rightarrow h(x_0)$. 51 | 52 | К сожалению, бывает так, что в одну и ту же ячейку попало много элементов (матожидание числа коллизий порядка $\frac{n^2}{m}$, где $m$~--- размер хэш-таблицы). Мы будем называть это коллизиями. 53 | 54 | Коллизии можно решать двумя способами, соответствующие хэш-таблицы имеют \textbf{открытую} или \textbf{закрытую} адресацию. 55 | 56 | \paragraph{Закрытая адресация} (или решение коллизии методом цепочек) --- в каждой ячейке храним список, в который будем добавлять соответствующие элементы. Матожидание длины списка будет порядка $\frac{n}{m}$. 57 | 58 | Хэш-таблица работает линейно от числа элементов, которые в ней когда-либо были, поэтому динамическая хэш-таблица работает за амортизированное время. 59 | 60 | <>-концепция --- если внутренние параметры системы бьют тревогу, сделаем глобальное изменение. В случае хэш-таблицы, если в таблице сейчас $m$ элементов, создадим новую хэш-таблицу удвоенного размера, в которую перехэшируем оставшиеся элементы. 61 | 62 | \textit{Замечание.} Очень часто разработчик не хочет амортизированное время работы, потому что боится внезапного <>, потому что это выключает систему на длительное время. Пример --- финал TI8. 63 | 64 | \paragraph{Открытая адресация} 65 | \hspace{\fill} 66 | 67 | Делаем вид, будто коллизий не бывает (то есть, в каждой ячейке храним только одно значение). Кроме того, рядом с ячейкой храним ключ элемента (или -1, если там пусто). Тогда если мы хотим найти элемент $x$, мы смотрим в ячейку $h(x)$, и идем от нее вправо до тех пор, пока не встретим $x$ или $-1$. 68 | 69 | Ожидаемое время --- это $\frac{1}{1 - \alpha}$, где $\alpha = \frac{n}{m}$. На практике все считают, что время --- константа. 70 | 71 | Удаление с открытой адресацией --- нетривиальная задача, потому что удаление элемента рушит цепочки. 72 | 73 | Удаление без <> --- удаляем все элементы от нашего элемента до ближайшей -1, но потом вернем их обратно с помощью добавлений 74 | 75 | Удаление с <> --- кроме пометки -1 делаем пометку <<зарезервирована>>. Тогда при удалении элемента мы ставим в его ячейку пометку <<зарезервирована>>. Тогда при линейном проходе мы делаем вид, что резерв --- это настоящий элемент, а при добавлении мы можем записать в резерв. Резерв включается в параметр $\alpha$, поэтому нам понадобится делать перестройки. 76 | 77 | Кроме линейного сканирования можно делать что-то типа <<прыжкам по хешу>> ($h(x) + j h'(x)$), но на практике линейное сканирование --- наш бро. 78 | 79 | \paragraph{Совершенное хэширование} 80 | \hspace{\fill} 81 | 82 | Нам изначально дано сколько-то ключей, мы хотим делать $get(x),\ set(x, y)$ за гарантированные $O(1)$ с ожидаемым $O(n)$ на преподсчет. 83 | 84 | Сделаем хэш-таблицу с закрытой адресацией. В каждой ячейке ожидаемое $O(1)$ элементов. Сделаем новую хэш-функцию, которая переносит все элементы из $l_i$ в ячейки размера $l_i^2$. Вероятность коллизии при таком хэшировании меньше $\frac{1}{2}$, поэтому мы будем просто рандомить хэш-функцию, пока не получим отсутствие коллизий, что займет у нас ожидаемое $O(1)$. 85 | 86 | \paragraph{Фильтр Блума} 87 | \hspace{\fill} 88 | 89 | $insert, get$ 90 | 91 | Запросы $get$ работают необычным образом~--- No $\rightarrow$ No; Yes $\rightarrow$ Yes($1-p$)/No($p$). То есть, если структура говорит, что элемент в ней лежит, то он в ней точно не лежит. Дальше минимизируется $p$. 92 | 93 | Фильтр Блума является массивом из битов длины $m$. Фильтр выбирает $k$ хэш-функций, элементу сопоставляется $k$ значений хэша. 94 | 95 | $insert$ --- в каждое из $k$ значений ставим 1 96 | 97 | $get$ --- проверяем, что во всех $k$ значениях стоит 1. 98 | 99 | \textbf{Время работы.} $k \sim \frac{m}{n}$. Рассмотрим вероятность ложноположительного срабатывания. Вероятность того, что клетка свободна --- $(\frac{m-1}{m})^{kn}$. Тогда вероятность ложноположительного срабатывания это $(1 -(\frac{m-1}{m})^{kn})^k \sim (1 - e^{-\frac{kn}{m}})^k$. 100 | 101 | Путем долгих вычислений получаем $k = \ln 2 \cdot \frac{m}{n}$. 102 | 103 | Кроме того, ФБ поддерживает операции пересечения и объединения множеств. 104 | 105 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_11_1212.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 12.12} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Деревья поиска} 46 | \hspace{\fill} 47 | Храним структуру данных, которая должна уметь делать все то же самое, что можно делать с отсортированным массивом, но еще с добавлением-удалением. 48 | 49 | \paragraph{Binaary search tree (BST)} 50 | 51 | Корневое дерево. В вершине храним левого сына, правого сына, предка, ключ. 52 | 53 | Обозначения: 54 | \begin{itemize} 55 | 56 | \item $l(v)$ --- левый сын 57 | 58 | \item $r(v)$ --- правый сын 59 | 60 | \item $p(v)$ --- предок 61 | 62 | \item $key(v)$ --- ключ 63 | 64 | \item $T(v)$ --- поддерево 65 | 66 | \item $S(v) = |T(v)|$ --- размер 67 | 68 | \item $A(v)$ --- множество предков 69 | 70 | \item $seg(v) = [\min_{u \in T(v)} key(u); \max_{u \in T(v)} key(u)]$ 71 | 72 | \end{itemize} 73 | 74 | Условие BST: 75 | 76 | $$ \forall u \in T(l(v)):\ key(u) < key(v)$$ 77 | 78 | $$ \forall u \in T(r(v)):\ key(u) > key(v)$$ 79 | 80 | То есть, ключи лежат в порядке лево-правого обхода (в порядке <<выписать левое поддерево - выписать вершину - выписать правое поддерево>>) 81 | 82 | $v \in seg(u) \leftrightarrow v \in T(u)$ 83 | 84 | Поиск в дереве --- надо сделать спуск. То есть, если текущая вершина --- не та, которая нам нужна, то можно понять, где лежит нужная нам, с помощью условия BST. 85 | 86 | Нахождение следующего --- либо спуск вправо, либо подъем по предкам до первого большего. 87 | 88 | Основная проблема --- операции вставки/удаления, которые должны делать дерево сбалансированным (таким, высота которого нас устраивает, то есть примерно $\log n$) 89 | 90 | \paragraph{Декартово дерево} 91 | 92 | У каждой вершины будем хранить не только ключ, но и какой-то приоритет $y$. Построим дерево так, что по $y$ это куча, а по $x$ это BST. 93 | 94 | Тогда декартово дерево задается однозначно, если определить все приоритеты. Почему? Расставим точки на плоскости в соответствии с $(x, y)$, после чего найдем корень. У корня будет наименьший приоритет и поэтому он определяется единственным образом (будем считать, что приоритеты различны). Тогда к корню нужно приписать слева и справа по дереву, которые рекурсивно строятся в левой и правых частях. 95 | 96 | \textbf{Утверждение} Если взять случайные $y$, то матожидание глубины дерева $O(\log n)$ 97 | 98 | \textbf{Доказательство:} Нет. 99 | 100 | \textbf{Утверждение} Если взять случайные $y$, то матожидание глубины каждой вершины $O(\log n)$ 101 | 102 | \textbf{Доказательство.} Матожидание высоты вершины --- это число вершин, которые являются ее предками. Вершина $i$ будет предком вершины $j$, если $y_i = \max \{y_i, y_{i+1}, \dots, y_j\}$. Матожидание суммы таких величин для $i$ это $\rangesum{j=0}{i-1} \frac{1}{i-j} + \rangesum{j=i+1}{n-1} \frac{1}{j-i} \le 2 \rangesum{i=1}{n} \frac{1}{i} = O(\log n)$ 103 | 104 | 105 | \end{document} 106 | -------------------------------------------------------------------------------- /tex_files/lec_12_1712.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 17.12} 42 | 43 | \begin{document} 44 | \paragraph{2-3 Дерево} 45 | 46 | \hspace{\fill} 47 | 48 | Представляет собой структуру данных, которая является сбалансированным деревом поиска, удовлетворяющее двум условиям: 49 | 50 | \begin{itemize} 51 | 52 | \item Все листья будут на одной глубине, значения будут храниться в листьях 53 | 54 | \item У всех вершин число исходящих ребер $deg_v \in \{0, 2, 3\}$ 55 | 56 | \end{itemize} 57 | 58 | Также мы в каждом поддереве будем хранить максимум, а детей будем хранить упорядоченными по величине максимума. 59 | 60 | \paragraph{Операции на дереве: поиск} Спуск будем делать рекурсивно. Поскольку мы хранили максимум, то мы среди детей находим первое число, большее $x$, спускаемся в соответствующего сына. 61 | 62 | \paragraph{Операции на дереве: добавление} Если степень предка после добавления стала равна 4, то создадим два сына размеров 2 и 2, и рекурсивно рассмотрим отца. Если дошли до корня, то создадим новый корень степени 2. 63 | 64 | \paragraph{Операции на дереве: удаление} Рассмотрим ситуации, которые могли возникать при удалении. Заметим, что у вершины есть отец, дедушка, дядя, брат (предок, другой сын прапредка, прапредок, другой сын предка). 65 | 66 | Если у вершины было 2 брата, то после ее удаления ничего менять не надо. 67 | 68 | Если у вершины был 1 брат, то нарушается инвариант на степени. Посмотрим на детей дяди. Если их было 3, то можно перераспределить 3 + 1 как 2 + 2, и инвариант не нарушится. Если же там было 2 ребенка, то склеимся в одну вершину степени 3, и уменьшим степень предка на 1. Рекурсивно запустим процесс балансировки от него. 69 | 70 | 71 | 72 | \paragraph{Оптимальное дерево поиска} 73 | 74 | Обозначим число детей за $d$. Тогда операции работают за $d \cdot \log_d n$. Найдем точку минимума: $(d \cdot \log_d n)' = \ln n \cdot \frac{\ln d - 1}{\ln^2 d}$. Нулевой корень производной при $d=e$. Таким образом, 2-3 дерево достаточно близко к оптимальному. 75 | 76 | 77 | \paragraph{$B+$ дерево} 78 | 79 | Зафиксируем константу $T$. Все значения опять храним в листьях. У вершин (кроме корня) степень от $T$ до $2 \cdot T - 1$. $2 \le deg_{root} \le 2 \cdot T - 1$ 80 | 81 | Обычно $T$ делают достаточно большим, чтобы дерево работало во внешней памяти. 82 | 83 | \paragraph{Операции: вставка} 84 | 85 | Если у вершины степень стала $2T$, то мы можем разделить ее на две вершины, подвесить их к предку, и рекурсивно запустить процесс у предка. 86 | 87 | \paragraph{Операции: удаление} 88 | 89 | Плохая ситуация при удалении --- степень предка стала равна $T - 1$. Посмотрим на соседних братьев. Если один из них по степени больше $T$, то мы можем позаимствовать у него крайнего сына, чем починим свою степень. Если же у обоих братьев степень $T$, то мы можем смерджить себя с братом, после чего рекурсивно продолжить процесс в предке, потому что у предка степень уменьшилась на 1. 90 | 91 | \paragraph{Почему $B+$, а не $B$?} В начале стоит сказать, что $B$-дерево обладает схожей структурой, но разрешает хранение значений не только в листьях. Его глубина не более чем на 1 меньше, чем у соответствующего ему $B+$-дерева. Но при этом элементы $B+$-дерева можно поддерживать в двусвязном списке, что удобно, а также можно итерироваться во внешней памяти. 92 | 93 | \end{document} 94 | 95 | -------------------------------------------------------------------------------- /tex_files/lec_12_1812.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage[T2A]{fontenc} 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[russian]{babel} 5 | \usepackage[pdftex]{graphicx} 6 | \usepackage{amsfonts} 7 | \usepackage{amsmath} 8 | \usepackage{fancyhdr} 9 | 10 | 11 | \author{Иваник Даниил} 12 | \title{Лекция12} 13 | \pagestyle{fancy} 14 | \fancyhf{} 15 | \fancyhead[LE,RO]{Иваник Даниил} 16 | \fancyhead[RE,LO]{Семинар АиСД 17.12} 17 | \begin{document} 18 | Научимся в детермиированный, так сказать, декартач. 19 | 20 | 2-3 дерево 21 | 22 | В этом дереве есть вершины степени 2 и вершины степени 3. Элементы записываются только в листьях. 23 | 24 | Ряд условий 2-3 дерева: 25 | 26 | 1)Все листья на одной и той же глубине. 27 | 2)Степень каждой внутренней вершины либо 2, либо 3. 28 | 29 | В промежуточных вершинах храним ключи, которыми можно разделять вершины-сыновей. 30 | 31 | У вершины с 3 детьми, два ключа - максимум поддеревьев двух первых детей, с 2 детьми - максимум в первом (а ещё храним максимум во всём поддереве). 32 | 33 | Смотря на ключ, мы можем понять в какое из двух (или трёх) деревьев идти. 34 | 35 | Вставка в 2-3 дерево. 36 | 37 | Найдём место, в котором элемент должен быть и просто вставим его. Может случиться, что детей уже было 3, а теперь стало 4. Тогда разобьём нашу вершину (у которой стало 4 сына) и разобьём её на 2 и переподвесим их теперь к её матушке. Ну и продолжаем это процесс пока не дойдём до корня. Если вдруг мы рассплитили корень, то создадим новый корень и подвесим к нему наши две вершины. После того, как мы всё сделали, можно запуститься рекурсивно вверх от только что вставленной и идём вверх. Это работает быстро, потому что уровней логарифм. 38 | 39 | Удаление из 2-3 дерева. 40 | Найдём элемент и тупо удалим его. Если у его предка было три ребёнка - всё хорошо. Предположим, что у вершины было 2 ребёнка, а остался один (трагично, не правда ли?). Теперь начинаются боль и мучения. В общем тут перебор случаев, который можно разобрать кроме того случая, когда у нас только один брат, у которого ровно два сына. Тогда мы переподвешиваем нашего сына к брату и переходим на уровень выше. Если мы упрёмся в корень, то просто возьмём корень и удалим его за ненадобностью. 41 | 42 | Всё 2-3 дерево можно провязать двусвязными списками, связывающие вершины на одном уровне. 43 | 44 | Почуму бы вместо 2-3 дерева не сделать бы 5-11 дерево? Оценим это так. Пусть у всех вершин степень d. Тогда стоимость операции: 45 | 46 | \[d \cdot \log_d{n} = d \cdot \frac{\ln{n}}{\ln{d}} \Rightarrow\] 47 | \[(d \cdot \log_d{n})^{'} = (d \cdot \frac{\ln{n}}{\ln{d}})^{'} \Rightarrow\] 48 | \[(d \cdot \log_d{n})^{'} = (d \cdot \frac{\ln{d} - 1}{(\ln{d})^2})^{'}\] 49 | 50 | 0 производной в \(d = e\). Значит, 2 и 3 - то хорошие приближения. 51 | 52 | \(B+\) - дерево. 53 | 54 | Степень каждой вершины от \(t\) до \(2t - 1\). 55 | Степень корня - от \(2\) до \(2t - 1\). 56 | 57 | Поиск вершины - также. 58 | 59 | Такие деревья нужны для алгоритмов во внешней памяти. 60 | 61 | Тогда ассимптотика - \(O(CPU \cdot (d \log_d{n}) + HDD \cdot \log_d{n})\). 62 | Тогда, хочется брать достаточно большой \(d\). 63 | 64 | Вставка: 65 | 66 | Ищем место для вставки и смотрим, куда вставить. Если в какой-то момент стало \(2t\) детей, то сплитим на \(t\) и \(t\) и переподвешиваем. 67 | 68 | Удаление: 69 | Пусть в вершине теперь стало \(t - 1\) детей (иначе всё хорошо). Если у нас соседний брат - "Большой Брат" (хотя бы \(t + 1\) ребёнок), то всё - мы нашли жертву, которую будем грабить (переподвешиваем одного из сыновей брата к нашей вершине). Если нет, то вдохновившись небезызвестным произведением Кена Кизи, подкидываем брату \(t - 1\) кукушонка. Переходим на уровень выше и продолжаем процесс рекурсивно. Отдельно оговорим корень. Тут проблема только тогда, когда у него осталась 1 вершина, но тогда корень улетает в небытие, и в этом городе появляется новый корень (время для нового Жожо). 70 | 71 | А сейчас будет нерекурсивная вставка в \(B\)-дерево. 72 | Ослабим ограничения на вершины теперь границы это \(t - 1\) и \(2t - 1\). Во время поиска вершины будут разбиваться в момент спуска. Как только вершина может переполниться (её степень \(2t - 1\)), тогда разобьём нашу вершину на \(t - 1\) и \(t\) и пойдём дальше вниз. 73 | 74 | Ещё одна отсечка, от которой плкавится мозг - в каждой вершине нам надо хранить массив максимумов детей. Будем хранить эту вещь бинарным деревом поиска (ДД). 75 | 76 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_13_1401.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 14.01} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Задачи на отрезке.} Введем какую-то произвольную операцию $\oplus$, и будем отвечать на запросы $get(l,\,r)$ на массиве $a$, ответом на которые будет $a_l \oplus a_{l+1} \oplus \dots \oplus a_r$. Также введем операцию изменения на отрезке $a_i := change(a_i,\,x)$. 46 | 47 | Потребуем от $\oplus$ ассоциативность ~--- $a \oplus (b \oplus c) = (a \oplus b) \oplus c$. 48 | 49 | \paragraph{Префиксные суммы.} Если в задаче нет запросов изменения (и элементы образуют группу, то есть есть обратный элемент), то посчитаем $p_i = p_{i-1} \oplus a_i$. Тогда ответ на запрос~--- это $p_r \oplus p_{l-1}^{-1}$. Если операция некоммутативна, то нужно будет пострадать, но вроде бы можно просто сделать $p_{l-1}^{-1} \oplus p_r$. Построение за $O(n)$, запрос за $O(1)$. 50 | 51 | \paragraph{Sparse table.} Если элементы не образуют группу, но задача все еще статическая, то можно сохранить значения, соответствующие $\oplus$ по всем отрезкам длины $2^k$. Тогда, когда нужно ответить на запрос $get(l,\,r)$, можно взять перекрывающиеся отрезки $[l,\,l + 2^i)$ и $(r - 2^i,\,r]$. От операции требуется $a \oplus b = b \oplus a$ и $a \oplus a = a$. \textit{Есть модификация, позволяющая обойтись без второго свойства.} Построение за $O(n \log n)$, запрос за $O(1)$. 52 | 53 | \paragraph{Segment tree.} Хотим к предыдущей задаче добавить обновление в точке. Хотим сохранить какое-то множество отрезков $S$, чтобы потом по нему восстанавливать ответ на произвольном отрезке $[l,\,r]$, склеивая не более чем $O(\log n)$ отрезков. Также должно быть не более $O(\log n)$ отрезков, содержащих какой-либо элемент. 54 | 55 | Построим двоичное дерево над массивом, где вершина на глубине $i$ будет отвечать за отрезок длины $2^{k-i}$, где $n = 2^k$. Разбивать запросы на отрезки будем таким образом: рассмотрим все отрезки внутри запроса, и выкинем вложенные. На каждой глубине мы возьмем не более двух отрезков, поэтому суммарно запросы будут работать за $O(\log n)$. 56 | 57 | \includegraphics{pictures/segtree.png} 58 | 59 | Реализация будет такой --- сделаем рекурсивную функцию $get$, которая хочет обойти дерево, зайти во все <<ключевые>> отрезки запроса, и посчитать итоговый ответ. Для $get(v,\,l,\,r)$ бывает три случая: 60 | \begin{itemize} 61 | \item $v$ не отвечает ни за что из отрезка $[l,\,r]$, поэтому не делаем ничего и прекращаем работу. 62 | \item $[l,\,r]$ содержит отрезок вершины $v$, и тогда можно обработать этот отрезок и прекратить работу. 63 | \item Иначе надо спуститься в детей, и повторить процесс 64 | \end{itemize} 65 | 66 | \paragraph{Lazy propagation.} Пусть у нас появился запрос $change$, модифицирующий отрезок. Будем хранить в вершине пометки вида <<мы хотели сделать со всеми детьми такую-то операцию изменения>>, которые мы изначально будем проставлять с запросом изменения на все <<ключевые отрезки>>. При этом во время запроса изменения мы по сути не сделаем изменений, только проставим пометки. Но теперь мы при каждом обращении к вершине проталкиваем модификатор (если есть) вниз, и меняем текущее значение $value$. Таким образом, после проталкивания все величины остаются валидными (кроме тех, которые находятся где-то глубоко в дереве, но к которым мы не спустились). 67 | 68 | \textit{Иначе говоря, мы считаем, что перед тем, как обратиться к какой-то вершине, мы обязаны обратиться ко всем вершинам-предкам, и тогда можем гарантировать, что в ней будут храниться актуальные значения параметров.} 69 | 70 | Требования к lazy propagation~--- дистрибутивность операции $change$ относительно $\oplus$, а также модификаторы также должны являться полугруппой. 71 | 72 | 73 | \end{document} 74 | -------------------------------------------------------------------------------- /tex_files/lec_14_1601.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 16.01} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Запросы на деревьях.} Будем обсуждать две задачи: \textbf{LCA} и \textbf{LA}. 46 | 47 | Постановка задачи $LCA$: даются запросы на вычисления наименьшего общего предка двух вершин $v,\,u$. То есть, ответ на запрос~--- это вершина наибольшей глубины такая, что она является предком и $v$, и $u$. 48 | 49 | Постановка задачи $LA$: даются запросы на вычисления предка вершины $v$ на глубине $k$. 50 | 51 | \paragraph{Двоичные подъемы.} Для каждой вершины преподсчитаем $p_{v,i}$, которая будет хранить информацию о том, какая вершина является $2^i$-ым предком вершины $v$. Насчитать их можно с помощью обхода дерева за $O(n \log n)$. 52 | 53 | Решение задачи $LA$ с помощью двоичных подъемов тогда будет таким: разложим число $k$ на степени двойки, и сделаем соответствующие <<прыжки>>: $v \rightarrow p_{v,i_1} \rightarrow p_{p_{v,i_1}, i_2} \rightarrow \ldots$. 54 | 55 | Решение задачи $LCA$ будет таким: сначала мы выровняем вершины по глубине. Иначе говоря, решим задачу $LA$, чтобы после ее решения вершины запроса имели одинаковую глубину (при этом мы хотим двигать только более глубокую вершину). Теперь, когда вершины на одной глубине (и если не совпали!), мы будем двигаться по степеням двойки от больших к меньшим таким образом: Если $LA_{2^i}$ наших вершин не совпали, то тогда поднимем вершины запроса на $2^i$. Такой процедурой мы найдем таких предков вершин $u$ и $v$, которые не совпадают, находятся на одной глубине, и при этом имеют общего предка. Этот предок и будет ответом на задачу. 56 | 57 | Решение с двоичными подъемами работает за $O(n \log n)$ преподсчета и $O(\log n)$ на запрос для обеих задач. 58 | 59 | \paragraph{Offline.} Решить $LA$ в оффлайн можно обходом в глубину с поддержкой стека за $O(n + q)$. Решение $LCA$ в оффлайн можно сделать с помощью алгоритма Тарьяна с СНМом (просто как факт) за $O((n + q) \alpha)$ 60 | 61 | \paragraph{Эйлеров обход.} Мысленно превратим каждое ребро в два ребра, одно из которых ориентировано вверх, а другое вниз. Тогда в таком графе можно сделать обход по типу Эйлерова~--- каждое ребро пройдем ровно один раз. Будем выписывать вершину $v$ каждый раз, когда проходим по ребру из $v$. 62 | 63 | \begin{center} 64 | \includegraphics{pictures/euler_path_on_tree.png} 65 | \end{center} 66 | 67 | Строго говоря, обход можно делать не из корня, а просто потом сделать циклический сдвиг, но обычно все запускают обход из корня и не парятся. 68 | 69 | Важное свойство~--- подотрезок нашего обхода является путем. При этом путь между $u$ и $v$ в эйлеровом обходе содержит $LCA(u,\,v)$ (потому что путь из $u$ в $v$ точно проходит через $LCA(u,\,v)$), а еще не содержит предка $LCA(u,\,v)$ (потому что по ребру в него проход был дважды, и если мы посетим его после $lca$, то мы уже не могли спуститься обратно). То есть, $LCA$ будет самой высокой вершиной на подотрезке обхода между $u$ и $v$. Это является сведением к задаче $RMQ$. Тогда с помощью sparse table можно получить решение за $O(n \log n + q)$. 70 | 71 | $LA$ тоже можно решать с помощью эйлерова обхода, делая спуск по дереву отрезков с поиском первой вершины на высоте хотя бы $k$. 72 | 73 | \paragraph{Метод четырех русских.} Пушка, которая решит нам $LCA$ за $O(n + q)$. Мы разобьем задачи на большие и маленькие. Нам не обязательно решать маленькие задачи при их появлении, если мы можем заранее решить все возможные маленькие задачи. 74 | 75 | \paragraph{$RMQ \pm 1$.} Заметим, что наше $RMQ$ при поиске $LCA$ обладала тем свойством, что $a_i = a_{i - 1} \pm 1,\ a_i \neq a_{i - 1}$. Разобьем массив на блоки размера $k$, в каждом блоке посчитаем максимум и получим массив $b_1,\ \ldots\ ,\ b_{\frac{2n}{k}}$. Насчитаем на нем разреженные таблицы. Также в блоке насчитаем префиксные и суффиксные максимумы. Теперь мы умеем за $O(1)$ отвечать на все запросы, кроме тех, которые полностью лежат в одном блоке. 76 | 77 | Для решения такой задачи мы посчитаем все возможные последовательности из $\pm 1$ длины $k$, там возьмем все подотрезки, и для них за линию решим. То есть за $O(2^k \cdot k^3)$. Можно, наверное, и лучше, но нам пофиг. 78 | 79 | Теперь положим $k = \lceil \frac{\log n}{2} \rceil$. Тогда маленькая задача решится за $O(\sqrt{n} \cdot \log^3 n)$. А для большой задачи преподсчет будет работать за $O(\frac{n}{k} \log n) = O(n)$. Таким образом, задача решена за $O(n + q)$. 80 | 81 | Решение произвольного $RMQ$ делается с помощью $RMQ \rightarrow LCA \rightarrow RMQ \pm 1$. Первый переход делается с помощью построения ДД на массиве с помощью стека. Тогда $RMQ$ на отрезке это $LCA$ для соответствующих вершин. 82 | 83 | \paragraph{Ladder decomposition.} Предложим другое решение задачи $LA$. Разобьем дерево на пути таким образом: возьмем самую высокую вершину, которая еще не покрыта путями, и возьмем из нее самый глубокий путь вниз. Также насчитаем двоичные подъемы. Такое можно решить за $O(n \log n)$. Каждый путь выпишем явно. 84 | 85 | После этого мы мысленно удвоим все пути. Возьмем и выпишем еще столько же вершин вверх для каждого пути. Общая память все еще линейна. 86 | 87 | Теперь пусть нам надо сделать подъем на $k$. Найдем наибольшее $i$ такое, что $2^i \le k$, сделаем такой прыжок. После чего мы оказываемся в вершине, самый глубокий путь из которой вниз был по длине не меньше, чем $2^i$. Это значит, что ответ на задачу хранится в выписанном пути для этой вершины и его можно найти за $O(1)$. 88 | 89 | \end{document} 90 | -------------------------------------------------------------------------------- /tex_files/lec_15_2301.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | \newcommand{\integral}{{\displaystyle \int}} 26 | 27 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 28 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 29 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 30 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 31 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 32 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 33 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 34 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 35 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 36 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 37 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 38 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 39 | 40 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 41 | 42 | \makeatletter 43 | \newenvironment{sqcases}{% 44 | \matrix@check\sqcases\env@sqcases 45 | }{% 46 | \endarray\right.% 47 | } 48 | \def\env@sqcases{% 49 | \let\@ifnextchar\new@ifnextchar 50 | \left\lbrack 51 | \def\arraystretch{1.2}% 52 | \array{@{}l@{\quad}l@{}}% 53 | } 54 | \makeatother 55 | 56 | \ifx\pdfoutput\undefined 57 | \usepackage{graphicx} 58 | \else 59 | \usepackage[pdftex]{graphicx} 60 | \fi 61 | 62 | \pagestyle{fancy} 63 | \fancyhf{} 64 | \fancyhead[LE,RO]{Макоян Артем (c редакцией @kikos), ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 65 | \fancyhead[RE,LO]{Лекция по алгоритмам 23.01} 66 | 67 | \begin{document} 68 | 69 | {\Large\tb{Персистентность}} \\ 70 | 71 | Есть структура данных T и операции. Некоторые операции изменяют T, а некоторые не изменяют. Тогда можно говорить о версиях структуры T в разные моменты времени. \ti{Персистенность} - это свойство структуры данных делать запросы к старым версиям. \\ 72 | 73 | \tu{Уровни персистентности}: 74 | 75 | \begin{itemize} 76 | 77 | \item $parital (weak)$ - версии образуют цепочку, то есть каждая следующая версия - это измененная предыдущая (запросы изменения можно делать только к последней версии). \\ 78 | \item $full (strong)$ - версии образуют дерево (запросы изменения можно делать к любой версии). \\ 79 | \item $fuctional (confluent)$ - поддерживаются операции сразу для нескольких версий (допустим $merge$ для версий декартова дерева). \\ 80 | 81 | \end{itemize} 82 | 83 | \tb{Персистенный массив}. \\ 84 | 85 | Для каждой клеточки храним вектор пар $(t_x, v_x)$ - в момент $t_x$ мы изменили этот элемент массива на $v_x$ (храним в порядке возрастания $t_x$). Бинпоиском отвечаем на запрос \ti{узнать значение элемента версии $t$}. \\ 86 | 87 | Такая персистентность $partial$, но не $full$ и $functional$. \\ 88 | 89 | \tb{Pointer machine}. Способ организовать структуру данных. Будем хранить все в узловой структуре, поддерживая связи между ними с помощью указателей. Тогда вместо изменения вершины мы просто создаем новую. Таким образом, чтобы изменить вершину $x$, нужно изменить суммарно $O(h)$ вершин. Такая структура данных будет, очевидно, $full\ persistent$. 90 | 91 | 92 | \begin{centering} 93 | \begin{tabular}{c} 94 | \includegraphics[width=300px]{pictures/pointer_machine.jpeg} \\ 95 | \textit{Малополезная картинка} 96 | \end{tabular} 97 | \end{centering} 98 | 99 | 100 | \tb{Full персистентный массив.} Давайте создадим двоичное дерево над массивом размера $n$ с высотой $O(\log n)$, реализовав его как pointer machine. Тогда теперь мы можем сделать изменение произвольного элемента в произвольной версии, получив $O(\log n)$ времени работы (и очевидную реализацию персистентного ДО в придачу). 101 | 102 | \tb{Персистентное декартово дерево}. \\ 103 | 104 | Заметим, что наше декартово дерево можно было бы реализовать через pointer machine, что даст нам что-то очень похожее на то, что мы хотим от такой структуры данных. К сожалению, такая структура данных не будет $functional\ persistent$, потому что есть конструктивный способ очень сильно расширить дерево в высоту (достаточно просто мерджить одну и ту же вершину с последней версией дерева, получая бамбук). 105 | 106 | Проблема у нас возникла в тот момент, когда мы воспользовалиь старой идеей приоритетов. Теперь будем вычислять что-то типа приоритетов динамически. А именно, будем считать, что приоритет дерева $L$ больше приоритета дерева $R$, если $rand() < \frac{S(L)}{S(L) + S(R)}$. Можно показать, что теперь высота ДД все еще $O(\log n)$. 107 | 108 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_16_2801.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 28.01} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Задачи оптимизации.} Во всех предыдущих задачах на структуры данных мы работали, оптимизируя какую-либо очевидную задачу (например, сумму на отрезке). Теперь же мы будем решать задачи, которые непонятно как решать, кроме как полным перебором всех вариантов ответа. 46 | 47 | В качестве примера возьмем задачу $subset\ sum$. В ней нам нужно найти подмножество заданного множества с фиксированной суммой $S$. Если перебрать все подмножества, и посчитать сумму по каждому подмножеству. 48 | 49 | Перебором можно решить любую задачу, если перебрать все возможные ответы (множество вещественных чисел для нас тоже конечно!). 50 | 51 | Подмножества хочется как-то пронумеровать. К сожалению, непонятно как закодировать $2^n$ чисел, если раньше мы разрешали в $RAM$-модели числа до $C^k \cdot n^k \cdot A$. Поэтому мы просто уточним $RAM$-модель, и разрешим $C^k \cdot t(n)^k \cdot A$ (Считая $t(n)$ таким временем работы, что внутри нет длинной арифметики). 52 | 53 | \paragraph{Динамическое программирование.} Иногда бывает полезно запоминать промежуточные величины перебора. Более того, часто перебор можно <<ужать>>, если нам в переборе нужны не все величины (например, в задаче <> достаточно помнить только общую сумму, если перебирать элементы по очереди). 54 | 55 | Сделаем $dp(i, x) \in \{0, 1\}$, которая будет говорить, можно ли набрать сумму $x$ с помощью первых $i$ элементов. Тогда $dp(i, x)$ можно пересчитать через $dp(i - 1, x)$ и $dp(i - 1, x - w_i)$. 56 | 57 | Требования к нашей динамике: 58 | \begin{itemize} 59 | \item Граф вычислений ацикличен. 60 | \item <<Состояния>> динамики явно задают нам всю необходимую информацию. 61 | \end{itemize} 62 | 63 | \paragraph{Задача о рюкзаке.} Пусть нам заданы $n,\ S,\ w_i,\ c_i$ (то есть элементы с весами и стоимостями). Мы хотим выбрать некоторое подмножество с суммарным весом не более $S$ и максимальной суммой стоимостей. 64 | 65 | Мы можем сделать динамику $dp(i, w, c) \in \{0, 1\}$, которая решит нашу задачу. Но заметим, что наше решение монотонно по параметру $c$ (то есть, для равных $i$ и $w$ стоит отдавать предпочтение ответу с максимальным $c$). Тогда $c$ можно сделать \textit{значением} динамики. То есть, пересчитывать динамику $dp(i,w) \in C$ как максимум из $dp(i - 1, w)$ и $dp(i - 1, w - w_i) + c_i$. Кстати, заметим, что тут задача монотонна по всем параметрам сразу. 66 | 67 | \paragraph{Задача коммивояжера (TSP).} Заданы точки на плоскости. Надо найти кратчайший кольцевой маршрут, проходящий по всем точкам хотя бы единожды. 68 | 69 | Есть очевидное решение за $O((n-1)!)$. Воспользуемся ДП по подмножествам, основная идея которого --- понять, что нам в состоянии важнее всего только то, в каком \textit{множестве} вершин мы уже были, и в каких вершинах мы уже оказались. Закодировать множество мы можем с помощью двоичной маски. Решение с такой идее отработает уже за $O(2^nn^2)$. 70 | 71 | \paragraph{ДП по подстрокам.} Отдельный трюк, когда подстроки пересчитываются через свои подотрезки. Важное отличие в том, что мы можем пересчитываться через несколько задач сразу ($dp(l, r) = dp(l, k) + dp(k, r)$), а за счет этого порядок пересчета на графе может быть неочевидным. 72 | 73 | \end{document} 74 | -------------------------------------------------------------------------------- /tex_files/lec_17_3001.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 30.01} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Meet-in-the-middle.} Пусть нам при решении задачи динамического программирования нужно найти кратчайший путь из $s$ в $t$ на графе вариантов. Перебрать весь граф из вершины $s$ может быть тяжело с точки зрения вычислений. Мы попробуем запустить поиск сразу из двух вершин --- из $s$ в прямую сторону, и из $t$ в обратную. Тогда любая общая вершина для двух наших переборов задает путь из $s$ в $t$. 46 | 47 | \paragraph{Subset sum.} Применим данную технику в задаче $subset sum$. Поделим множество предметов на две равные группы. Тогда за $2^{\frac{n}{2}}$ мы можем найти все возможные суммы для каждой из двух групп элементов. Теперь за $O(2^{\frac{n}{2}})$ переберем все суммы $x$ для первой группы, и с помощью хэш-таблицы проверить наличие $S - x$ для второй группы. 48 | 49 | \paragraph{Рюкзак.} Примерно то же самое можно сделать для задачи о рюкзаке, только теперь нам понадобится узнавать максимум на префиксе. 50 | 51 | \paragraph{Максимальная клика в графе.} Клика --- связный подграф. Мы хотим найти максимальную клику в графе. Разобьем граф на две доли (левую и правую, размерами в пополам). Теперь посчитаем $dp_{submask}$ --- максимальную подклику для подмножества вершин. Тогда, зная пересечение списков смежности по всем подмножествам вершин, мы можем поступать следующим образом: находить клику в левой доли, брать множество ее соседей в правой доле, и смотреть на соответствующее значение $dp$. 52 | 53 | \paragraph{Компактность динамики.} Будем считать динамику \textit{компактной} по какому-то из измерений, если для пересчета значений динамики нужно помнить \textit{не очень много} слоев по этому параметру. Например, динамика для НОП будет компактной по обоим параметрам (и там, и там достаточно помнить всего пару слоев). 54 | 55 | 56 | \end{document} 57 | -------------------------------------------------------------------------------- /tex_files/lec_18_0602.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АИСД 06.02} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Оптимизационные задачи.} Часто человечество занимается тем, что берет перебор, и пытается сделать этот перебор оптимально возможным, чтобы работало ну очень-очень быстро. Для примера подобной задачи часто решают задачу коммивояжера (TSP), которая не имеет решения лучше, чем за экспоненту, но при этом современными методами решается для $n \sim 200$. Задача, между тем, актуальная, потому что транспортные компании, вот это все. Что должен сделать хороший перебор: 46 | \begin{itemize} 47 | \item Запоминать промежуточные решения, чтобы у нас была возможность экстренно остановить перебор. 48 | \item Поставить отсечения таким образом, чтобы не идти в те состояния, где \textbf{точно} не будет решений. 49 | \end{itemize} 50 | 51 | \paragraph{Задача о ферзях.} Пусть мы хотим расставить $n$ ферзей на доске $n \times n$. Как закодировать состояние? Можно, например, с помощью $2n$ координат. Заметим, что гораздо лучше зафиксировать перестановку, а потом делать ферзей $(i, p_i)$. Тогда такие ферзи гарантированно не бьют друг друга по вертикали или горизонтали. Остается только проверить диагонали. Тогда если перебор будет строить перестановку слева направо, то мы сможем <<отрезать>> некоторые состояния (например, не ставить ферзя в те клетки, которые еще не бились предыдущими ферзями). 52 | 53 | \paragraph{Branch \& bound method.} Мы будем оптимизировать две вещи: 54 | 55 | \paragraph{Границы.} Нам хочется понимать, когда мы сможем отрезать ветку перебора, чтобы не упустить оптимальный ответ. Например, выходить из ветки, если текущий ответ превышает нынешний оптимальный. Идеально --- ввести соответствующую функцию $f(p)$, и делать так: 56 | \begin{minted}{c++} 57 | if (cur + f(p) > best) { 58 | return; 59 | } 60 | \end{minted} 61 | 62 | Такая функция должна, в случае задачи TSP, возвращать такую длину пути, который нам \textbf{точно} понадобится пройти. Например, можно взять вес остовного дерева на оставшихся вершинах. Тогда $span \le TSP \le 2 \cdot span$. Хорошая функция оценки! 63 | 64 | Кроме того, очень хорошо иметь нормальное приближение ответа $best$. То есть, изначально как-нибудь (отжигом, жадником, итд) найти неплохой ответ, чтобы перебор не шел в заранее ущербные шаги. 65 | 66 | \paragraph{Ветви.} Тут мы хотим сделать какую-то магию, чтобы перебирать ветки в правильном порядке. То есть, мы хотим запускать самые хорошие ветви в самом начале, особенно на первых слоях. Например, можно ввести оценочную функцию, и запускать перебор в порядке сортировки по этой оценочной функции. В задаче TSP, из физических соображений, можно запускать перебор сначала из ближайшей вершины к текущей. Также можно попытаться прыгнуть сразу на много уровней вниз, соптимизировав это какой-то простой динамикой ($dp_{mask, i, j}$ --- наименьшая длина пути через всю маску, если мы начали в $i$ и закончили в $j$) на маленьких подмножествах-кластерах. Тогда мы знали самый хороший способ взять какое-то подмножество, а тогда мы вместо $2^k$ ходов сделаем $k$ ходов. 67 | 68 | В ветвях есть много пространства для спекулятивных переборов. Например, можно идти в топ-$k$ веток по оценочной функции. 69 | 70 | Можно инициализировать решение для неспекулятивного перебора решением из спекулятивного перебора! 71 | 72 | \end{document} 73 | -------------------------------------------------------------------------------- /tex_files/lec_19_1102.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 11.02} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Решаем задачи на графе.} Задачи о поиске максимальной клики, максимального независимого множества и минимального контролирующего множества сводятся друг к другу, поэтому если мы решили одну задачу (за какое-то $O(f(n))$), то и другие задачи решили. Будем решать задачу о поиске минимального вершинного покрытия. 46 | 47 | \paragraph{Асимптотические оптимизации, которые не казались такими сначала.} Задачу о вершинном покрытии можно решать за $O(2^n m)$: для каждой вершины решаем, берем мы ее или нет: 48 | 49 | $$t(G, V) = t(G \setminus v, V \cup \{v\}) + t(G \setminus v, V)$$ 50 | 51 | Заметим, что если мы решили не брать какую-то вершину в ответ, то мы обязаны взять всех ее соседей. Тогда мы можем решать задачу на каком-то меньшем графе, а именно: 52 | 53 | $$t(G, V) = t(G \setminus v, V \cup \{v\}) + t(G \setminus \{v \cup N(v)\}, V \cup N(v))$$ 54 | 55 | Рассмотрим максимальную степень вершины в графе $maxd$. Если, $maxd = 0$, то задача решается за $O(1)$. Тогда пусть $maxd \ge 1$. Таким образом, во втором случае число вершин уменьшается на два: 56 | 57 | $$t_n = t_{n - 1} + t_{n - 2}$$ 58 | 59 | Получили решение за $O(\phi^n m)$, как оценка на числа Фибоначчи. 60 | 61 | Давайте сделаем теперь $maxd \ge 2$ --- когда у нас остались ребра, для каждого ребра возьмем одну вершину: 62 | 63 | $$t_n = t_{n - 1} + t_{n - 3}$$ 64 | 65 | $$x^3 - x^2 - 1 = 0$$ 66 | 67 | Получили $O(1.47^n m)$. 68 | 69 | Если $maxd = 2$, то граф разбивается на пути и циклы, в которых поиск вершинного покрытия тривиален. Аналогично получаем решение за $O(1.38^n m)$. 70 | 71 | \paragraph{Перебор в антагонистических играх.} Нам дано полное двоичное дерево четной глубины $2n$. Фишка стоит в корне дерева. Каждый игрок на своем ходу перемещает фишку налево или направо. В каждом листе написано <<0>> или <<1>>, причем мы не знаем значения в листах заранее, а можем только спрашивать у оракула (который не играет против нас, то есть неадаптивный). 72 | 73 | Решение за $4^n$ запросов выглядит так: спросить про все листья, а потом посчитать на дереве динамику на выигрыш-проигрыш: 74 | 75 | $$t_v = \begin{cases} 1 &\text{если } t_{v_l} = 0 \lor t_{v_r} = 0 \\ 0 & \text{иначе} \end{cases}$$ 76 | 77 | Это решение можно соптимизировать. Заметим, что если мы нашли переход из вершины в проигрышного сына, то второго сына можно не рассмотривать, поэтому какие-то листья мы можем просто не посещать. 78 | 79 | Введем $t_n$ --- матожидание количества посещенных листьев для глубины $2n$. 80 | 81 | Для начала рассмотрим $t_1$ и все шесть конфигураций: 82 | 83 | \begin{center} 84 | \begin{tabular}{c|c} 85 | Листья & матожидание \\ 86 | $[0, 0, 0, 0]$ & $2$ \\ 87 | $[0, 0, 0, 1]$ & $2.5$ \\ 88 | $[0, 1, 0, 1]$ & $3$ \\ 89 | $[0, 0, 1, 1]$ & $2.5$ \\ 90 | $[0, 1, 1, 1]$ & $2.75$ \\ 91 | $[1, 1, 1, 1]$ & $3$ \\ 92 | \end{tabular} 93 | \end{center} 94 | 95 | Заметим, что за каждый спуск на два уровня вниз, мы рассматриваем в среднем не более трех детей. Тогда $t_n \le 3 \cdot t_{n -1} \le 3^n$ 96 | 97 | \paragraph{$\alpha \beta$-отсечение.} Проведем предыдущее рассуждение на минимаксной игре (это такая, где в листьях записаны числа, первый игрок хочет минимизировать итоговое число, а второй максимизировать). Введем параметры $\alpha$ и $\beta$ --- гарантии игроков. $\beta$ --- это минимальное число, которое первый игрок может себе гарантировать (то есть первый игрок знает, что не получит больше, чем $\beta$). Аналогично $\alpha$ --- это максимальное число, которое гарантирует себе второй игрок). У нас должен соблюдаться инвариант $\alpha \le \beta$, потому что остальные состояния неиграбельные. Как в них можно попасть по ходу перебора? Если в какой-то момент один из игроков сделает невыгодный для себя ход. Понятно, что при оптимальной игре обоих игроков они не будут делать невыгодные для себя ходы. 98 | 99 | Как пересчитываются $\alpha$ и $\beta$? В листе $\alpha = \beta = get(v)$. Если второй игрок может пойти в состояние со стоимостью $x$, то он может сделать $\alpha = max(\alpha, x)$. Аналогично первый игрок будет уменьшать $\beta$. При этом эти гарантии будут переходить в сыновей вершины, но не в предков --- в предки будут переходить только значение вершины (которое мы либо явно посчитали, либо вообще не сччитали, потому что состояние было неиграбельно). 100 | 101 | 102 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_20_1302.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Лекция АиСД 13.02} 42 | 43 | \begin{document} 44 | 45 | \paragraph{DFS.} Алгоритм обхода графа. Каждой вершине присваивается один из трех цветов --- белый, серый или черный. Белые вершины мы еще не рассматривали, серые вершины мы рассматриваем сейчас, черные вершины мы больше не рассматриваем. Алгоритм примерно такой: 46 | \begin{enumerate} 47 | \item Покрасить текущую вершину в серый цвет. 48 | \item Рекурсивно запуститься из всех белых вершин, соединенных с нашей. 49 | \item Покрасить текущую вершину в красный цвет. 50 | \end{enumerate} 51 | 52 | Что-то из важных утверждений про $dfs$: 53 | 54 | \begin{itemize} 55 | \item Серые вершины образуют путь. 56 | \item Ребро между двумя серыми несоседними вершинами существует тогда и только тогда, когда в графе есть цикл. 57 | \item Из черных вершин нет ребер в белые. 58 | \end{itemize} 59 | 60 | \paragraph{Топологическая сортировка.} Пусть у нас есть ориентированный ациклический граф. Давайте выпишем такую перестановку вершин --- $p_v$ будет номером покраски вершины $v$ в черный цвет. Тогда все наши ребра будут идти только справа налево. 61 | 62 | \paragraph{Поиск компонент сильной связности и конденсация.} Компонентой сильной связности называем такой класс эквивалентности, гда $v$ и $u$ сильно связаны, если есть пути $u \rightarrow v$ и $v \rightarrow u$. Конденсацией мы назовем такой мета-граф, где все компоненты сильной связности <<сжаты>> в одну вершину, а ребра между новыми компонентами есть, если есть ребра между какой-то парой вершин из этих компонент. Такой граф уже точно будет ацикличным. 63 | 64 | Сделаем процедуру, аналогичную топсорту, но теперь у нас ребра уже могут идти слева направо. Про самую последнюю вершину в новом порядке мы знаем, что она точно лежит в компоненте истока. Рассмотрим граф $G'$, построенный на обратных ребрах. Тогда если у нас есть ребро в $G'$ справа налево $u \leftarrow v$, то это значит, что вершины $u$ и $v$ лежат в одной компоненте сильной связности. Тогда мы можем последовательно выделять КСС с помощью обхода по обратным ребрам. 65 | 66 | 67 | 68 | \end{document} 69 | -------------------------------------------------------------------------------- /tex_files/lec_21_2002.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 20.02} 45 | 46 | \begin{document} 47 | 48 | \paragraph{2-sat.} Автор опоздал на эту часть лекции, поэтому напишет ее сам позднее. 49 | 50 | \paragraph{Мосты и точки сочленения.} Назовем мостами такие ребра, при удалении которых граф теряет связность. Аналогичные вершины определим как точки сочленения. Как их найти? Сделаем dfs в неориентированном графе, и построем дерево dfs. Те ребра, по которым мы не переходили, мы назовем обратными. В дереве dfs эти ребра будут идти из вершины в ее какого-то предка. 51 | 52 | Что тогда верно про мосты? Из поддерева ребра-моста нет ни одного обратного ребра, которое шло бы выше, чем наше ребро. А найти самое высокое ребро в поддереве можно обычной динамикой. Аналогично с точками сочленения. 53 | 54 | \paragraph{Отношения вершинной и реберной двусвязности.} Проще всего запомнить так --- отношения вершинной двусвязности это отношение на ребрах, а отношение реберной --- отношение на вершинах. 55 | 56 | Вершины $v$ и $u$ находятся в одной компоненте реберной двусвязности, если существует реберно-простой цикл, содержащий $u$ и $v$. 57 | 58 | Отношение такой двусвязности транзитивно. Можно показать, что если $u \equiv v$ и $v \equiv w$ (при этом $v$ и $w$ соединены ребром), то и $u \equiv w$. Для этого надо склеить два цикла, и найти в них новый --- из $u$ в $w$. 59 | 60 | Чтобы найти классы эквивалентности, можно удалить все мосты в графе. 61 | 62 | Отношение вершинной двусвязности определяется аналогично, но на ребрах. 63 | 64 | \paragraph{Задача о поиске кратчайшего пути.} 65 | 66 | Пусть нам дан граф $G = (V,\ E)$. Каждому ребру задан какой-то вес, а весу пути соответствует суммарный вес всех ребер на пути. 67 | 68 | Веса на ребрах могут быть естественными (неотрицательные), или не естественными (разрешаем отрицательный вес ребер). Также отдельный случай для нас --- существование циклов отрицательного веса. Кроме того, мы иногда хотим искать любые пути, иногда реберно простые, иногда вершинно простые. 69 | 70 | \paragraph{Bfs.} Пусть мы хотим найти кратчайший путь, где вес каждого ребра равен 1. Идея такая --- мы хотим построить слоистую декомпозицию, где уровню $i$ соответствуют вершины на расстоянии $i$ от стартовой. Алгоритм реализуется на очереди. 71 | 72 | 73 | 74 | \end{document} 75 | -------------------------------------------------------------------------------- /tex_files/lec_22_2502.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 25.02} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Кратчайшие расстояния в графе.} В большинстве задач мы считаем, что циклов отрицательного веса нет, оптимальный путь простой, а на кратчайшие расстояния накладывается неравенство треугольника. 49 | 50 | \paragraph{Алгоритм Форда-Беллмана.} Задача --- найти кратчайшие расстояния из $s$ до всех вершин графа. Мы хотим на каждом шаге перебирать все ребра, и поддерживать инвариант --- для шага $i$ мы считаем, что алгоритм нашел кратчайшие расстояния среди всех путей длины $i$. Тогда на следующем шаге мы рассмотрим все ребрра, и продолжим старые пути новыми ребрами, сделаем релаксации. 51 | 52 | \paragraph{Циклы отрицательного веса.} Заметим, что наш алгоритм не будет делать релаксации после шага $n$, потому что больше будет нечего релаксировать. Но в случае с циклами отрицательного веса это не так --- мы знаем, что на каждом шаге после $n$-го мы будем делать релаксацию, проходя по улучшающему ответ циклу. Тогда, если мы для каждой релаксации запомнили, какая вершина улучшала наш текущий ответ, мы можем восстановить цикл (или оптимальный путь), просто проходясь по предкам. 53 | 54 | \paragraph{Алгоритм Флойда.} Задача --- найти матрицу кратчайших расстояний. Пусть $f_k(u, v)$ --- это кратчайшее расстояние между $u$ и $v$, если в качестве промежуточных вершин разрешено использовать вершины $1, \ldots, k$. Тогда при переходе $f_k(u, v) \rightarrow f_{k+1}(u, v)$ мы хотим сделать релаксацию пути как $u \rightarrow k + k \rightarrow v$. 55 | 56 | \paragraph{Алгоритм Дейкстры.} В реальных задачах редко присутствуют ребра отрицательного веса, и в таких ситуациях часто используется алгоритм Дейкстры. Инвариант алгоритма --- известны кратчайшие расстояния от $s$ до вершин множества $A$. Мы знаем, что $\max\ p(v) \le \min\ p(u),\ v \in A,\ u \in V \setminus A$. Давайте для всех вершин поддерживать какое-то текущее $p(v)$. Понятно, что для вершин из $A$ это будет итоговым ответом. Утверждается, что в $A$ можно добавить вершину с минимальным текущим $p(v)$. Доказательство от противного --- если текущее расстояние до $v$ было не кратчайшим, то в $v$ был путь, проходящий через вершину $u \in V \setminus A$, но тогда $p(u) < p(v)$, противоречие. 57 | 58 | Тогда мы хотим добавлять вершины в $A$ по очереди, по ходу обновляя значения $p(v)$ для всех соседей добавляемой вершиной. Тогда нам нужна структура данных, которая сделает $n$ извлечений минимума и $m$ уменьшений ключа. Оптимальная структура (асимптотически!) --- фибоначчиева куча, с ней алгоритм работает за $O(n \log n + m)$. 59 | 60 | \paragraph{Потенциалы.} Создадим новый граф, где каждой вершине зададим потенциал $c_v$. Теперь за вес ребра примем $w_c(u, v) = w(u, v) + c_v - c_u$. То есть, вес ребра плюс разность потенциалов. Тогда длина пути $s \rightarrow t$ в новом графе определяется как длина в старом графе с дополнительным слагаемым $c_t - c_s = \text{const}$. 61 | 62 | Задача о размещении потенциалов эквивалентна поиску отрицательного цикла. То есть, если цикл отрицательного веса есть, то не существует потенциалов, для которых выполняется неравенство треугольника (например, вес такого цикла в новом графе будет меньше нуля). Если же циклов нет, то сделаем $c_v = p(s, v)$. Тогда $w_p(u, v) = w(u, v) - p(v) + p(u)$, но $p(v) \le p(u) + w(u, v)$, а тогда вес новых ребер положителен, а неравенство треугольника выполнено. 63 | 64 | \paragraph{A-star.} Пусть мы хотим решить задачу на плоскости, при этом хочется не посещать заведомо бесполезные состояния. Введем какую-то метрику $d(u, v)$, в качестве которой введем евклидово расстояние. Теперь мы вытаскиваем новые вершины по минимуму $p(u) + w(u, v) + d(v, t)$ (то есть минимальная сумма расстояния и оценки на метрику). Здесь $t$ - это вершина, кратчайший путь в которую мы пытаемся найти. Поскольку на метрику введено неравенство треугольника, то наша новая Дейкстра все еще работает. 65 | 66 | \paragraph{Двусторонняя Дейкстра.} Аналогично обычной Дейкстре, запускаем алгоритм в две стороны, и обновляем ответ, если видим ребро $u \leftrightarrow v,\ v \in B,\ u \in A$. 67 | 68 | \end{document} 69 | -------------------------------------------------------------------------------- /tex_files/lec_23_2702.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 27.02} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Остовные деревья.} Пусть нам дан взвешенный граф. Мы хотим оставить в нем подмножество ребер минимального суммарного веса так, чтобы граф оставался связным. 49 | 50 | \textbf{Лемма о безопасном ребре:} Для подмножества вершин $A$ есть ребро наименьшего веса, ведущее в дополнение к $A$. А именно, ведет из $u \in A$ в $v \notin A$. Существует остов, содержащий это ребро. Доказательство: От противного. Пусть мы не взяли ребро $u \leftrightarrow v$. Посмотрим на путь из $u$ в $v$ в дереве. В какой-то момент там нашлось ребро из $A$ в $V \setminus A$. Тогда можно удалить это ребро и заменить его на $v \leftrightarrow u$ --- стоимость не увеличится. 51 | 52 | \paragraph{Алгоритм Прима.} По аналогии с алгоритмом Дейкстры будем поэтапно строить множество $A$ и добавлять в него минимальное ребро из леммы. Но тут важно, что лемма не гарантирует нам, что итоговый ответ хороший, потому что она говорила нам только о том, что ребро принадлежит какому-то ответу. Но есть усиленная версия леммы --- если ребро меньше по весу, чем все остальные, то тогда оно обязательно будет в минимальном остове. Поэтому надо как-то неявно задать веса ребер, чтобы они были различны (это в реальной жизни не нужно, только для доказательства), после чего алгоритм Прима нам уже будет гарантировать минимальный ответ. 53 | 54 | \paragraph{Система непересекающихся множеств.} Структура данных, которая поддерживает следующие операции: 55 | 56 | \begin{itemize} 57 | \item $get(v)$ --- узнать, в каком множестве находится элемент $v$ 58 | \item $union(v, u)$ --- объединить множество, содержащее $v$ с множеством, содержащим $u$. 59 | \item $check(v, u)$ --- проверить, находятся ли элементы в одном и том же множестве. Выражается через два $get$-а. 60 | \end{itemize} 61 | 62 | 63 | \paragraph{Алгоритм Краскала.} В начале упорядочим ребра по весу. Будем поддерживать какое-то множество компонент связности. Если для очередного ребра компоненты вершин различны, то можно сделать $union$ в $dsu$. Работает за $O(sort(m) + union(n) \cdot n + check(n) \cdot m)$ 64 | 65 | \paragraph{Алгоритм Борувки.} Выделим для каждой вершины минимальное ребро. Теперь добавим все эти ребра в остов, и сожмем граф. Дальше сделаем аналогичную операцию. Повторяем, пока не сойдется до одной компоненты. Каждый раз вершины соединяются в компоненты хотя бы по две вершины. Это значит, что итоговая оценка сложности будет $O(m \log n)$. Заметим, что на плотных графах Борувка работает за $O(m)$ --- каждый раз число ребер уменьшается в два раза. 66 | 67 | Чтобы объединить две асимптотики, получим: 68 | 69 | $$\frac{n^2}{4^k} \le m$$ 70 | 71 | $$4^k \ge \frac{n^2}{m}$$ 72 | 73 | $$k \approx \frac{1}{2} \log \frac{n^2}{m}$$ 74 | 75 | Значит, через $k$ операций мы получим граф, который можем считать полным (а на нем мы работаем за линию!). Тогда асимптотика это $O(m \log \frac{n^2}{m})$. 76 | 77 | \end{document} 78 | -------------------------------------------------------------------------------- /tex_files/lec_26_1203.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 12.03} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Алгоритмы на графах во внешней памяти} Напомним, что мы хотим делать алгоритмы с менее, чем линейным числом обращения к памяти. Например, сложность $O(\frac{n\cdot Poly(log n)}{B})$ нас устраивает, а сложность $O(n)$ нас категорически не устраивает. Всякие $O(\frac{Poly(n)}{\sqrt{B}})$ или $O(\frac{Poly(n)}{\log{B}})$ нам не нравятся, но иногда мы не можем лучше. 49 | 50 | 51 | \paragraph{Dfs.} Если мы смогли сохранить ребра так, что для каждой вершины ребра лежат в памяти последовательно, то мы можем доставать соседей $v$ блоками. Но, к сожалению, это не делает сложность алгоритма хорошей, потому что у нас есть массив $used$, к которому нам придется обращаться. Обращения будут произвольными. Тогда, если $n < M$, то алгоритм имеет смысл, потому что мы можем сохранить массив в оперативной памяти, а иначе этот алгоритм работает за $O(n + \frac{m}{B})$. 52 | 53 | \paragraph{Работа со списками.} Имеем какой-то односвязный список. Он реализован как массив и указатели. То есть, в каждой ячейке массива есть указатель на следующую ячейку массива. Научимся с ним работать. 54 | 55 | \paragraph{Групповые операции.} Чтобы считать несколько значений из списка, мы можем либо спросить про каждый элемент запроса, либо про все элементы списка --- $O(q)$ или $O(\frac{n}{B})$. Чтобы сделать групповые изменения, можно отсортировать все запросы заранее, после чего обрабатывать запросы группами за линейное время блоками. Сложность будет равняться $O(sort(q, M, B) + \frac{n + q}{B})$. 56 | 57 | \paragraph{Задача list ranking.} Мы хотим для каждого элемента узнать его порядковый номер в соответствующем списке. Это тривиально делается в оперативной памяти, потому что мы можем просто пройти по списку. Но для внешней памяти алгоритм не подойдет --- прыжки по памяти произвольны. 58 | 59 | Во-первых, мы хотим сделать список двусвязным. Это то же самое, что и набор запросов <<Присвой следующему элементу мой индекс в поле предка>>. Групповой запрос на изменение мы уже научились обрабатывать. 60 | 61 | Теперь сделаем что-то типа двоичных подъемов. На итерации $k$ считаем, что мы правильно посчитали ранги для всех вершин, у которых ранг не более $2^k$. Кроме этого, будем поддерживать для всех вершин указатель на вершину на расстоянии $2^k$ от нее (и вперед, и назад). Как задать новые ранги? Для тех вершин, у которых уже известны ранги, есть суперссылка в вершину без ранга. Но тогда ее ранг --- это ранг старой вершины, увеличенный на $2^k$. Осталось пересчитать суперссылки. Их можно пересчитывать двоичными подъемами --- брать суперссылку от нашей суперссылки. Но у нас доступа в произвольную точку памяти. Поэтому мы сделаем так: пусть у нас есть вершина $v$, ее суперпредок $u$, и ее суперсын $w$. Тогда новый суперсын от $u$ это $w$, а суперпредок от $w$ это $u$. Это тоже операция групового присваивания. 62 | 63 | 64 | Пусть у нас был оракул, который умел говорить, четный или нечетный ранг для элемента. Пусть мы выкинули из списка все нечетные элементы, а указатели на следующий элемент списка теперь указывают на элемент <<через один>> от нас. Например, список $1 \rightarrow 3 \rightarrow 4 \rightarrow 2$ перейдет в $1 \rightarrow 2$. Мы уменьшили длину списка в два раза. Пусть мы посчитали ранги в четном списке. Тогда мы на самом деле знаем ранги и для нечетного списка тоже --- это просто ранг предка, увеличенный на единицу. Таким образом, мы получим сложность $t(n) = t(\frac{n}{2}) + sort(n, M, B)$. 65 | 66 | Как создать такого оракула? Мы сделаем его недетерменированным. А именно, для каждого элемента случайно решим, выкинем мы его или нет. Но нам нужно, чтобы для элемента остался в новом списке либо он, либо его предок. Тогда мы выкидываем элемент, только если мы случайно решили, что хотим выкинуть его, и случайно решили, что мы не хотим выкинуть его предка. Так мы отбросим четверть элементов. Получаем сложность $t(n) = t(\frac{3n}{4}) + sort(n, M, B)$. Так мы можем проталкивать величину <<чему равен номер моего списка>>. 67 | 68 | Но поскольку у нас нумерация сместилась произвольным образом, ранги пока что пересчитываются не так просто. Раньше мы просто умножали ранг на 2 и прибавляли 1, но сейчас мы не выкидывали некоторые элементы. 69 | 70 | Пусть рекурсия вернула наш новый список с рангами. Теперь мы для каждого нерассмотренного элемента знаем, чему должен быть равен ранг относительно предка. Но ранги предков сейчас поедут. Предварительно скажем, что ранг новых вершин --- это ранг предка, увеличенный на 1. После чего мы получили два массива рангов --- для старых вершин и для новых. Теперь нам надо сделать линейный проход, и при встрече равных рангов сначала брать старую вершину, а потом увеличивать все ранги на суффиксе на 1 (каким-нибудь счетчиком). По сути, мы просто избавились от равных чисел за сложность сортировки. Таким образом, мы решили list ranking за сложность $O(sort(n, M, B))$. 71 | 72 | \paragraph{Поиск минимального остова во внешней памяти с помощью алгоритма Борувка.} Отсортируем ребра по первой вершине. Теперь за $O(\frac{n}{B})$ мы находим минимальное ребро из каждой вершины. Теперь нам надо сделать самый сложный шаг --- найти компоненты. 73 | 74 | У нас есть какое-то множество ребер, которое задает лес. Мы хотим для каждой вершины узнать номер ее компоненты. Тогда мы потом сожмем компоненты, уменьшим размер в два раза, и тд (см. алгоритм Борувки). Разобьем каждое ребро на два ориентироанных, и для каждой вершины зададим каждому ребру следующее, как в эйлеровом обходе. Теперь мы получаем списки ребер, и нам надо для каждого ребра просто понять номер его списка. Видим, что это и есть задача list ranking. Таким образом, мы сможем найти остов за $O(sort(n, M, B) \log n)$. 75 | 76 | \end{document} 77 | -------------------------------------------------------------------------------- /tex_files/lec_27_0704.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 07.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Потоки.} Пусть нам дан некий ориентированный граф. У каждого ребра есть некоторая пропускная способность $c_{v, u}$ (можем полагать, что если ребра нет, то она равна нулю). Две вершины $s,\ t$ обозначены как сток и исток. 49 | 50 | Далее мы выделяем какое-то множество путей $P = \{p_1(s, t), p_2(s, t), \ldots\}$. Каждому пути сопоставляем число $f_i \ge 0$. Требуется, чтобы для каждого ребра $e$ сумма $f_i$ по всем вхождениям ребра в пути не превосходила $c_e$. При таких условиях мы максимизируем $\sum f_i$. 51 | \paragraph{Классический вид задачи.} Обозначим потоком функцию от пары вершин $f:\ V \times V \rightarrow \mathbb{R}$, на которую накладываются следующие требования: 52 | 53 | \begin{enumerate} 54 | \item $f(v, u) \le c(v, u)$ 55 | \item $f(v, u) = -f(u, v)$ 56 | \item $\forall v \in V \setminus \{s, t\}: \displaystyle \sum_{u} f(v, u) = 0$ 57 | \end{enumerate} 58 | 59 | Мы хотим максимизировать $|f| = \sum_{u} f(s, u) = \sum_{u} f(u, t)$. 60 | 61 | Можно заметить, что можно определить сумму потоков $f_1 + f_2$, если выполняется пункт 1. Остальные свойства сохранятся. 62 | 63 | Перевод из первой постановки задачи во вторую делается просто: вдоль каждого пути по прямым ребрам добавляем $+f_p$, а вдоль обратных ребер прибавляем $-f_p$. Тогда все три свойства выполнятся, и все хорошо. 64 | 65 | Определим $e_v = \displaystyle \sum_{u} f(v, u)$. Если мы выделим какое-то множество вершин, то поток, проходящий через множество равен сумме $e_v$. Можно заметить, что такое число это что-то из $\{0, |f|, -|f|\}$. 66 | 67 | Ребро называется насыщенным если $f(v, u) = c(v, u)$. Остаточной пропускной способностью ребра $c*(v, u)$ назовем $(c - f)(v, u)$. Остаточной сетью назовем граф на множестве ребер, для которых $c*(v, u) \neq 0$. 68 | \paragraph{Разрез.} Это такое разбиение вершин на множества $A$ и $\overline A$. Разрезы бывают ориентированные и неориентированные. В потоках мы почти всегда говорим про $s/t$-разрез --- $s \in A$, $t \notin A$, стоимость разреза определяем как $\displaystyle \sum_{v \in A} \sum_{u \notin A} c(v, u)$. 69 | 70 | Разрез называется насыщенным, если все его ребра насыщенные. 71 | \paragraph{Декомпозиция потока.} Поток можно представить в виде суммы $l \le m$ элементарных потоков (то есть путей и циклов). Доказательство конструктивное: пока общий поток ненулевой, из $s$ есть ребро, где $f > 0$. Проходя по нему, дальше тоже будет ребро с положительным потоком, итд. Получим путь $s \rightarrow t$, где можно уменьшить все $f$ на минимальное из потоков по ребрам. Если встретили цикл, то уменьшаем цикл, и продолжаем. Поскольку каждый раз добавлялось одно ребро с $f = 0$, то всего мы выделим не более $m$ элементарных потоков. В какой-то момент путей $s \rightarrow t$ не останется. Тогда в сети остались только циклы. Их можно выделить как элементарные потоки. Если нас интересует сведение второй постановки задачи к первой, то на циклы можно просто забить. 72 | 73 | Размер декомпозиции можно оценить как $O(nm)$ --- $O(m)$ итераций, и $O(n)$ вершин в элементарном потоке. Найти за это время декомпозицию тоже можно. Для этого надо хранить указатель на текущее интересное исходящее ребро для каждой вершины. Тогда наш указатель либо двигается вправо (суммарно $O(m)$), либо мы находим какой-то новый элементарный поток. То есть, каждый шаг декомпозиции работает за $O(n)$ переходов по ребру, и все сдвиги указателя суммарно работают за $O(m)$ по всем шагам декомпозиции, получаем сложность $O(nm)$. 74 | 75 | 76 | 77 | \end{document} 78 | -------------------------------------------------------------------------------- /tex_files/lec_28_1404.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 14.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Теорема Форда-Фалкерсона.} Теорема состоит из нескольких утверждений: 49 | \begin{enumerate} 50 | \item Максимальный поток равен минимальному разрезу 51 | \item Поток максимален, если не существует пути $s \rightarrow t$ в остаточной сети 52 | \end{enumerate} 53 | 54 | Давайте покажем первое утверждение. Для этого сначала скажем, что любой поток не больше любого разреза. Это верно, потому что размер разреза это сумма $\sum c_{v, u}$, а поток это $|f| = \sum f_{v, u}$ по $v \in A, u \notin A$. Теперь мы предъявим разрез, размер которого равен размеру какого-то потока --- тогда мы одновременно найдем и минимальный разрез, и максимальный поток. 55 | 56 | Пусть мы взяли какой-то существующий поток, в остаточной сети которого не было пути $s \rightarrow t$ (условие п.2). Тогда возьмем разрез, образованный насыщенными ребрами --- то есть возьмем в множество $A$ все вершины, достижимые из $s$ в остаточной сети. Тогда для всех ребер разреза $c_{v, u} = f_{v, u}$, то есть вес разреза совпал с величиной потока. Значит, такой поток максимален, а соответствующий разрез минимальный. 57 | 58 | \paragraph{Алгоритм Форда-Фалкерсона.} Самый простой алгоритм для поиска потока --- найти произвольный путь в остаточной сети и пустить поток вдоль него. Работает данный алгоритм за $O(|f| \cdot E)$, что не очень хорошо. Стоит заметить, что алгоритм сохраняет дробность решений --- то есть поток на целых чисел будет целым числом, для четных целых --- четным целым (потому что происходят только операции взятия минимума и вычитания). 59 | 60 | \paragraph{Алгоритм Эдмондса-Карпа.} Идея алгоритма в том, чтобы дополнять поток вдоль кратчайшего по ребрам пути из $s$ в $t$. Такой алгоритм имеет уже полиномиальную сложность. По сути, мы дополняем поток вдоль пути, который находится поиском в ширину. Для доказательства времени работы изобразим слоистую сеть, которую найдет bfs (то есть сгруппированные по расстояниям вершины). У нас есть ребра внутри одной компоненты, ребра в следующую, и ребра на сколько угодно назад. Утверждается, что при насыщении вдоль пути расстояние от $s$ до $v$ не уменьшается. Это верно, потому что при обновлении сети у нас удаляются какие-то ребра вдоль пути, и добавляются обратные. Следовательно, при старом разбиении на классы у нас не появляется ребер на два и более классов вправо, а значит расстояния могут только увеличиться. 61 | 62 | На каждой итерации алгоритма насыщается какое-то ребро. Надо заметить, что оно может насыщаться еще раз, но для этого сначала надо пустить поток по обратному ребру. Сколько раз это можно сделать? $O(V)$. Потому что мы насыщаем вдоль ребра слева направо (из $d$ в $d + 1$). Тогда, поскольку вершины двигаются только вправо, то не получится пустить по ребру $v \rightarrow u$ поток раньше, чем переместив $v$ и $u$ на слой вправо. А всего вершины могут быть удалены не более, чем на $O(V)$. Тогда мы делаем $O(VE)$ итераций, на каждой из которых вызываем $bfs$, получая оценку $O(VE^2)$. 63 | 64 | \paragraph{Алгоритм Диница.} Идея алгоритма Диница похожа на нашу предыдущую идею в декомпозиции потока. Если у нас уже есть зафиксированная слоистая сеть, то можно пускать поток вдоль пути, пока путь находится по ребрам между слоями. Тогда мы будем искать пути, пока слоистая сеть не потеряет связность, потом перестроим слоистую сеть, и так далее. Перестроек будет $O(V)$, потому что вершина $t$ каждый раз двигается хотя бы на слой вправо. На каждой итерации нам надо найти все пути с насыщениями. Насыщений, как можно заметить, не более $O(E)$. Хочется много раз запустить $dfs$, который найдет все пути. При этом если каждый раз запускать $dfs$ заново, то мы получим сложность $O(E^2)$. Но если запоминать указатель на первое нерассмотренное ребро, то сложность получится $O(VE)$. Почему? Потому что мы будем либо совершать неудачную попытку и двигать указатели к следующему в списке элементу, либо найдем путь длины $O(V)$. Операций первого рода суммарно будет как раз $O(E)$ на все запуски. 65 | 66 | \paragraph{Масштабирование.} Давайте попытаемся улучшить асимптотику другой техникой --- будем сначала искать большие потоки, а потом маленькие. А именно, давайте по очереди искать пути, по которым можно пустить хотя бы $2^k$ единиц потока. Тогда на каждой итерации у нас будет не более $2^k \cdot E$ единиц потока, при этом мы будем находить пути с потоком хотя бы $2^{k-1}$, что означает линейное от числа ребер число насыщений. Значит, Форд-Фалкерсон с масштабированием работает за $O(E^2 \log C)$. 67 | 68 | \end{document} 69 | -------------------------------------------------------------------------------- /tex_files/lec_29_1604.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 16.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Алгоритм Диница с масштабированием.} Аналогично Форду-Фалкерсону с масштабированием, будем по очереди запускать алгоритм Диница, ставя ограничения на величину остаточных пропускных способностей, необходимых для того, чтобы ребро попадало в остаточную сеть. Общий вид алгоритма будет выглядеть как-то так: 49 | 50 | \begin{minted}{c++} 51 | int max_flow() { 52 | for (SCALE = 1 << 30; SCALE > 0; SCALE >>= 1) { 53 | while (bfs(s, t)) { 54 | while(path = dfs(s, t)) { 55 | relax(path); 56 | } 57 | } 58 | } 59 | } 60 | \end{minted} 61 | 62 | Какую мы получим выгоду от масштабирования? При переходе между итерациями мы знаем, что величина текущего минимального разреза не больше, чем $2 \cdot SCALE \cdot E$. То есть мы знаем, что теперь у нас будет суммарно не более $O(E)$ насыщений в рамках одной итерации. 63 | 64 | Раньше мы оценивали Диница так: у нас был $dfs$, в котором мы считали число успешных и неуспешных итераций $a_i$ и $b_i$. Мы получали, что $\sum a_i = O(VE),\ \sum b_i = O(E)$. Сделаем новую оценку, используя тот факт, что насыщений всего $O(E)$. Здесь $t_d$ --- число путей длины $d$. 65 | 66 | $$\rangesum{d=0}{V} \rangesum{i=0}{t_d} (a_{d, i} + b_{d, i}) \le \rangesum{d=0}{V} (d \cdot t_d + E) \le VE + V \cdot \rangesum{d=0}{V} t_d = O(VE)$$. 67 | 68 | В итоге на каждой итерации масштабирования мы сделаем $O(VE)$ шагов, получаем оценку на время работы $O(VE \log C)$. 69 | 70 | \paragraph{Оценки Карзанова.} Пусть в нашей сети единичные пропускные способности (например, в задаче о поиске максимального паросочетания). Тогда утверждается, что алгоритм Диница отработает за $O(E \sqrt{V})$. 71 | 72 | Как это показать? Сначала покажем, что в рамках одной слоистой сети алгоритм делает $O(E)$ шагов. Для этого надо оценить сумму $a_i$, которая не превышает $E$, потому что после каждого успешного действия с ребром оно насыщается (читай --- удаляется). 73 | 74 | Отдельно покажем, что если определить $P = \sum p(v, u)$ (где $p(v, u)$ --- потенциал вершины, сколько через нее максимально может пройти), то алгоритм Диница будет работать за $O(\sqrt{P} VE)$. 75 | 76 | Определим вершинный разрез как такое множество вершин, через которое будет проходить любой путь из $s$ в $t$. 77 | 78 | Сделаем первые $\sqrt{P}$ итераций Диница. Теперь в нашей сети будет не меньше, чем $\sqrt{P}$ слоев. Поскольку эти слои не пересекались, то оставшийся поток в сети не больше минимума потока через вершинные разрезы, то есть он не больше, чем $\sqrt{P}$. А значит, алгоритм Диница найдет не более чем $\sqrt{P}$ путей. Таким образом, мы получим сложность $O(\sqrt{P} VE)$. В применении к задаче о паросочетании $P = V$, а в рамках одной слоистой сети происходит не $O(VE)$, а $O(E)$ шагов, откуда получается сложность $O(E \sqrt{V})$. 79 | 80 | \paragraph{Стоимостные потоки.} Введем $w$ --- дополнительную стоимость потока вдоль ребра. Мы будем считать, что $w_{v, u} = -w_{u, v}$. Общей стоимостью назовем $\sum \frac{f_{v, u} \cdot w_{v, u}}{2}$ (у нас дважды учитывается поток вдоль одного ребра из-за обратных ребер). Обычно стоимость хотят минимизировать. 81 | 82 | Выделяют несколько задач: min-cost-flow, min-cost-k-flow, min-cost-max-flow. В первой мы минимизируем вес, во второй мы ищем минимальный вес потока величины $k$, а в третьей найти максимальный поток, а среди таких потоков поток минимальной стоимости. Есть еще задача о циркуляции минимальной стоимости, к которой все эти задачи сводятся, если замкнуть $t \rightarrow s$ правильно заданным ребром. 83 | 84 | \paragraph{Критерий оптимальности потока.} Поток считается минимальным по стоимости потоком размера $k$, если и только если в его остаточной сети нет циклов отрицательного веса. Почему? Ну пусть мы нашли какой-то другой поток размера $k$, который имел меньшую стоимость. Если рассмотреть $f_1 - f_2$, то это будет циркуляцией. Если рассмотреть ее декомпозицию, в ней будут только циклы, при этом стоимость отрицательная. Значит, какой-то из циклов имеет отрицательную стоимость. Противоречие. 85 | 86 | В доказательстве было узкое место: у нас могли нарушиться условия на пропускные способности, и поэтому не факт, что мы можем добавить этот новый цикл. Но на самом деле это правда, потому что $f_1$ и $f_2$ были корректными потоками. А именно, при добавлении у нас поток по ребру будет не больше чем максимум из потоков по ребру, что остается корректным потоком. 87 | 88 | \paragraph{Алгоритм поиска min-cost-k-flow.} Если у нас был поток $f$ минимальной стоимости веса $k$, то поток минимальной стоимости веса $k+1$ можно получить вдоль кратчайшего в плане стоимости пути в остаточной сети $G_f$. А это значит, что если мы сначала найдем минимальный поток веса 0 (брать отрицательные циклы, пока можем), а затем по очереди брать кратчайшие пути $p$ из $s$ в $t$. 89 | 90 | Почему утверждение верно? Пусть был какой-то другой поток лучше. Тогда это значит? Что $w(f_1) + w(p) > w(f_2)$. Рассмотрим разность между этими потоками. В ней есть отрицательный цикл $c$. Рассмотрим $p + c$. Если его декомпозировать, то получим пути, каждый из которых не дешевле, чем $p$ (потому что $p$ был кратчайшим), и циклы, которые имели неотрицательную стоимость (иначе ими можно было бы уменьшить $f_1$). Тогда это значит, что поток $p + c$ имеет стоимость не меньше, чем $p$, противоречие. 91 | 92 | 93 | \end{document} 94 | -------------------------------------------------------------------------------- /tex_files/lec_30_2104.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 21.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Алгоритм поиска min-cost max-flow.} В общем виде решение выглядит так --- найти минимальный по весу путь, после чего вдоль него дополнять поток. Поскольку в сети бывают ребра отрицательного веса (и отрицательные циклы!), то искать кратчайший путь надо алгоритмом Форда-Беллмана. Тогда решить задачу можно за $O(|F| \cdot VE)$. 49 | 50 | \paragraph{Алгоритм Джонсона.} Во многих задачах сеть имеет более простой вид. Например, в задаче о назначениях в сети нет отрицательных циклов. Если отрицательных цикл нет, то можно воспользоваться идеей про потенциалы. Давайте посчитаем кратчайшие расстояния от $s$ до всех остальных вершин. Тогда введем новый вес ребра, равный $w_{v, u} - \rho_u + \rho_v$ (их можно посчитать алгоритмом Форда-Фалкерсона). Таким образом, каждый вес ребра теперь не отрицательный. Поскольку вес любого пути $s \rightarrow t$ в новом графе --- это вес в старом графе, взятый с какой-то константой, то кратчайший путь в новом графе --- это кратчайший путь в старом. А такой кратчайший путь можно найти алгоритмом Дейкстры. После обновления вдоль пути у нас появятся обратные ребра, и потенциалы надо будет пересчитать. Как это делать? Заметим, что на кратчайшем пути цена всех ребер нулевая. А тогда цена обратных ребер тоже нулевая, и можно обновить кратчайшие расстояния через кратчайшие расстояния в новом графе. А именно, добавить к потенциалам кратчайшие расстояния в новом графе, которые мы тоже могли найти алгоритмом Дейкстры. В таком случае, сложность получается $O(|F| \cdot (E + V \log V) + VE)$, и в задаче о назначениях это дает асимптотику $O(V^3)$. 51 | 52 | 53 | \paragraph{Строковые алгоритмы.} Строкой мы будем называть конечную последовательность символов какого-то алфавита $\Sigma$. Если не сказано иного, то считать размер алфавита константой нельзя. 54 | 55 | \paragraph{Задача о подстановке шаблона.} Задача выглядит так: есть две строки $s$ и $t$. Надо найти позиции, с которых в строке $s$ можно прочитать строку $t$. При этом строка $t$ состоит из обычных символов алфавита, а также два специальных символа Джокер (символ '?', который означает любой символ, а также астериск '*', который означает любую строку, возможно пустую). Соответственно, можно ли заменить вопросики на буквы, а зведздочки на строки, чтобы получившаяся строка $\overline t$ входила в $s$. Решать такую задачу можно с помощью динамического программирования за $O(|s| \cdot |t|)$, где состояние --- это состояние вида <<сколько символов из каждой строки мы прочитали>>. 56 | 57 | \paragraph{Бор.} Структура данных, которая позволяет делать добавление-удаление-поиск строк за их размер. Она реализуется как дерево, где на каждом ребре написана буква, а строке соответствует путь из корня до вершины. Соответственно, в каждой вершине надо хранить переходы по всем ребрам. Тогда добавление-поиск-удаление делаются просто спуском в дереве, с созданием вершин, если пока что переходов соответствующих не было. И надо еще хранить терминальные пометки, которые говорят о том, заканчивалась ли какая-то строка из множества в текущей вершине. Тривиальная реализация будет хранить $O(L|\Sigma|)$ памяти. Можно хранить список всех детей в списке, и тогда $O(L | 58 | \Sigma|)$ времени, но линейная память. Можно создать хеш-таблицу с переходами в вершине, тогда линейно по обоим параметрам. Если сжать бор (то есть сжать вершины степени 1), то тоже эффективнее будет. 59 | 60 | \end{document} 61 | -------------------------------------------------------------------------------- /tex_files/lec_31_2804.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 28.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{$\pi$-функция.} Префикс-функция от строки $s$ определяется так: для каждой позиции $i$ это такая максимальная длина $l$, что $s_{0, l - 1} = s_{i - l + 1, i}$. То есть, мы берем наибольший префикс строки $s$, совпадающий с суффиксом, заканчивающимся в позиции $i$. При этом мы искусственно запрещаем делать $l = i + 1$ (то есть запрещаем брать префикс, совпадающий с суффиксом). 49 | 50 | Как эффективно вычислять эту функцию? Можно заметить, что $\pi_{i + 1} \le \pi_i + 1$. При этом нижней границы нет. То есть, если мы будем итеративно считать префикс-функцию, то значения у нас не могут увеличиваться больше чем на 1 на каждом шаге, поэтому суммарно уменьшаться на 1 они будут $O(n)$ раз. 51 | 52 | Тогда префикс-функцию можно считать, например, так: сначала положить $\pi_i = \pi_{i - 1} + 1$, а потом постепенно уменьшать, и делать проверку на равенство подстрок с помощью хэшей. Но стандартный алгоритм делает так: он по очереди пытается приписать символ к $\pi_{i - 1},\ \pi_{\pi_{i - 1} - 1},\ \ldots$. Это верно, потому что если строка максимальна, то ее надо было продлить относительно прошлой подстроки. Если так не получалось сделать (символы не совпадали), то надо было попробовать максимальную длину, которая подходит, после $\pi_{i - 1}$. Но это ровно и есть значение префикс-функции от $s_{\pi_{i - 1}}$, потому что $s_{0, l - 1} = s_{i - l + 1, i}$, и потому что мы запретили брать префикс, равный суффиксу. Тогда этот алгоритм так же работает за $O(|s|)$. 53 | 54 | Чтобы найти подстроку $t$ в строке $s$, можно запустить этот алгоритм на строке $t\$s$, после чего найти все точки, в которых $\pi_i = |t|$. Тут можно еще сэкономить память, и использовать только $O(|t|)$ памяти. 55 | 56 | \paragraph{Автомат префикс-функции.} Мы хотим, чтобы Кнут-Морис-Пратт (поиск подстроки в строке) работал неамортизированно. Для этого можно сначала насчитать все переходы, и потом делать переходы. А именно, мы хотим делать $go_{v, c}$ --- переход из вершины $v$ по символу $c$. Вершину $v$ мы будем отождествлять с префиксом длины $v$. Тогда, если $s_{v + 1} = c$, то $go_{v, c} = v + 1$, а иначе $go_{v, c} = go_{\pi_{v}, c}$. 57 | 58 | \paragraph{Z-функция.} В этот раз мы хотим найти для каждой позиции наибольший префикс $s_{0, n}$ и $s_{i, n}$. Тут функция монотонна, и ее можно считать наивно: пока можно увеличить значение, и оно корректно, надо увеличивать. Линейный алгоритм будет основан примерно на этом. 59 | 60 | Будем строить z-функцию итеративно. Тогда каждый шаг алгоритма давал нам новую подстроку $s_{i, i + z_i}$. Мы их будем обозначать за $l_i,\ r_i$. Поддерживать мы из них будем всегда тот подотрезок, у которого правая граница как можно больше. 61 | 62 | Тогда посмотрим на какое-то текущее $i$. Если $i \in [l, r]$, то $z_i \ge \min(r - i, z[i - l])$. Левое число нужно, чтобы мы не вышли за границу отрезка (потому что символы вне отрезка для нас неизвестные), а правое --- это то, как мы используем текущий отрезок $[l, r]$. А именно, поскольку мы знаем, что наша строка сейчас такая же, как и $s_{0, r - l}$, то можно <<подглядеть>>, чему было равно значение $z_{i'}$, где $i'$ соответствует парному символу для $i$. 63 | 64 | Дальше мы можем просто наивно увеличивать значение $z$-функции, и этого хватит для линейного времени. Время окажется линейным, потому что наивное увеличение надо использовать, только если $i + z_i = r$ (то есть, если мы хотим выйти за границы текущего отрезка). А это значит, что у нас сдвинется число $r$. Поскольку $r$ может сдвинуться не более, чем $n$ раз, то получаем оценку $O(|s|)$ времени и памяти. 65 | 66 | \end{document} 67 | -------------------------------------------------------------------------------- /tex_files/lec_32_3004.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 30.04} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Ахо-Корасик.} Хотим решать следующую задачу: Дан набор из $n$ строк $s_i$ суммарного размера $L$ на алфавите $\sigma$. Кроме этого, дан текст $t$, и задается вопрос насчет вхождений: сколько строк из набора входят в $t$ как подстроки? 49 | 50 | Первый шаг: построить бор на наборе строк. Теперь мы хотим сделать на этом боре детерменированный автомат. Автомат при чтении $t_{0}\ldots t_{i}$ должен переводить нас в вершину, которой соответствует самый длинный суффикс строки $t_{0}\ldots t_{i}$ из присутствующих в боре. 51 | 52 | Для каждой вершины $v$ создадим суффиксную ссылку $link$, которая будет вести в вершину, соответствующую самому длинному суффиксу $str(v)$, не совпадающему с $str(v)$, но присутствующему в боре. Кроме этого, обозначим переходы автомата за $go_c$. Тогда понятно, что $link_v$ можно найти, если посмотреть на суффиксную ссылку предка. А именно, если из суффиксной ссылки предка есть переход по символу, который написан на ребре $(p_v, v)$, то $link_v$ ведет именно туда. Если там перехода не было, то надо посмотреть на следующего предка в дереве суфссылок, и сделать аналогичную операцию. Но, если считать, что для предков посчитано $go_c$, то это то же самое, что взять $go_{c(p_v, v)}$ для $link_{p_v}$. 53 | 54 | Для того, чтобы считать переходы в автомате, тоже можно воспользоваться предыдущими значениями. А именно, если из $v$ есть ребро с символом $c$, то тогда $go_c$ будет указывать в конец ребра. Иначе следует посмотреть на $go_c$ для нашей суффиксной ссылки. 55 | 56 | Обе динамики можно посчитать либо лениво, либо с помощью обхода в порядке возрастания глубин. 57 | 58 | \paragraph{Оценка времени работы} Можно оценить как $O(m |\sigma|)$, где $m$ --- число вершин в дереве, потому что динамика занимает ровно столько памяти (тривиально), и для нее верно $time = memory$. Также есть оценка $O(L)$, которую можно получить, если показать, что у нас всего спусков бывает не более чем $O(L)$, а подъемов суммарно не больше, чем спусков. 59 | 60 | 61 | \end{document} 62 | -------------------------------------------------------------------------------- /tex_files/lec_33_1205.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 12.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Суффиксное дерево.} Суффиксным деревом мы будем называть сжатый бор, который будет хранить все суффиксы строки $s$, и только их. Сжатый бор — это бор, на ребрах которого написаны не буквы, а строки. Вместо строк мы будем хранить подотрезок $[l, l + len)$. Соответственно, если при добавлении строки оказывается так, что строка вдоль ребра не читается, то ребро нужно будет разделить на две части — общую и разную, и поставить между ними промежуточную вершину. 49 | 50 | Добавлять в наш сжатый бор мы будем все суффиксы строки. 51 | 52 | 53 | \paragraph{Квадратичный алгоритм.} Будем считывать строку посимвольно. На ребрах будут написаны подотрезки. Поскольку мы не знаем число $n$, мы введем подотрезки $[l, \infty)$. 54 | 55 | Алгоритм будет хранить все терминальные вершины в боре, и при добавлении нового символа будет продлевать все суффиксы строки на этот символ. Понятно, что все терминалы, в которые вели ребра $[l, \infty)$, можно никак не продлевать. Те суффиксы, которые лежали не на бесконечных ребрах, надо продлить на новый символ $c$. Если перехода нет, надо создать новую вершину, и сделать в нее ребро $[l, \infty)$. 56 | 57 | Разделим суффиксы на определившиеся, неопределившиеся и неизвестные. Неизвестные — это суффикс, который еще не добавлен в бор. Определившийся суффикс — это такой суффикс, которому соответствует ребро $[l, \infty)$. Неопределившиеся — это такие суффиксы, которые являются префиксом определившегося суффикса. Будем называть их суффиксами 2, 1, и 0 типа (от определившихся к неизвестным). 58 | 59 | Понятно, что суффиксы типа 2 не перестают быть типом 2 — это самый префикс такого типа. Тип 0 переходит в 1 или 2. 1 может переходить в 2. При этом важно понимать, что суффиксы всегда будут иметь вид 222221111110000. Почему? Потому что после какой-то единицы всегда будут идти единицы — если для позиции $i$ суффикс $s_i$ встречался раньше (на позиции $j < i$). то для $s_{i+1}$ можно увидеть, что $s_{j+1}$ соответствовал этому суффиксу. 60 | 61 | \paragraph{Алгоритм Укконена.} 62 | 63 | В терминологии 0-1-2 суффиксов мы хотим следующее: поддерживать в боре все 1 и 2-суффиксы, при этом каждый раз рассматриваать только первый по счету 1-суффикс. При переходе по новому символу самый левый 1-суффикс может поменяться. Еслии он поменялся, то нам надо заменить подотрезок из 1-суффиксы на 2-суффиксы. Так мы получим амортизированную линейную сложность. 64 | 65 | Тогда мы будем поддерживать указатель на $j$ --- первый 1-суффикс в дереве. Если мы видим переход, которого сейчас нет в боре, надо разделить ребро на два (если мы сейчас находимся в середине ребра). После этого из вершины делаем переход по новому симполу. Теперь суффикс имеет тип 2. Сейчас осталось проделать аналогичную операцию для $j + 1$. Проблема в том, что непонятно, где находится соответствующий суффикс. 66 | 67 | Введем суффиксные ссылки. Суффиксная ссылка из вершины $v$ указывает на \textit{позицию} в боре, которая соответствует суффиксу $v$, который на 1 короче текущего. То есть, для перехода мы сможем пользоваться суффиксными ссылками. Осталось понять, как их поддерживать. 68 | 69 | Суффиксная ссылка из вершины всегда ведет в вершину. Это верно, потому что вершина соответствовала разветвлению, но тогда и для строки на 1 короче это тоже будет верно. 70 | 71 | Пусть мы сейчас хотели сделать переход по суффссылке из вершины $v$. Посмотрим на $u = link(parent(v))$. Если мы прочитаем из вершины $u$ ребро $parent(v) \rightarrow v$, то окажемся в позиции $link(v)$. Это либо будет вершиной, либо в ней сейчас произойдет ветвление. Причем чтение ребра надо реализовать за число вершин на пути, не за число символов. 72 | 73 | За сколько это будет работать? Амортизированно за линию. Понятно, что нас интересует сейчас только суммарное время на чтение по ребрам во время поиска суффссылок. Тут можно ввести потенциал $p(j)$ --- число символов на ребре до предка-вершины $j$. Тогда, когда мы при чтении ребра проходим каждую вершину, мы уменьшаем свой потенциал. 74 | 75 | \end{document} 76 | -------------------------------------------------------------------------------- /tex_files/lec_34_1405.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Семинар АиСД 14.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Формальные грамматики и языки.} Обозначим алфавит символов за $\sigma$, а множество конечных строк за $L \subset 2^{\sigma^*}$, где $\sigma^*$ --- это все последовательности конечной длины. 49 | 50 | \paragraph{Регулярные выражения.} Тривиальные регулярные выражения: $\empty$ (пустое множество) $\epsilon$ (пустая строка), $x \in \sigma$. Остальные регулярные выражения определяются рекурсивно относительно них. А именно, мы также разрешаем $A + B$ (последовательная запись), $A | B$ (выбор из двух регулярок), $A*$ (повторение строки из языка $A$ $0, 1, 2, \ldots$ раз) Звездочка еще называется замыканием $Kleene$. 51 | 52 | Например, $\{0|1|2|3\}*+\{0|1|2|3\}$ это множество всех непустых строк из символов $\sigma=\{0, 1, 2, 3\}$. 53 | 54 | \paragraph{Способы задания языков.} Регулярные выражения, ДКА, НКА, $\epsilon$-НКА. Эти способы эквивалентны. Очевидно $L_{\text{ДКА}} \subset L_{\text{НКА}} \subset L_{\text{$\epsilon$-НКА}}$ Вложенность $\epsilon$-НКА в ДКА можно показать, если рассмотреть алгоритм приведения одного автомата в другой. Например, можно выделить все подмножества вершин НКА как отдельные вершины ДКА (то есть, он будет иметь экспоненциальный размер). Тогда переход по ребру --- это то же самое, что взять все вершины подмножества, и объединить переходы по ребрам из них. Еще стоит следить за переходами по пустому символу, потому что вершина сразу задает подмножество вершин, достижимых из нее по $\epsilon$-ребрам. 55 | 56 | Осталось показать, что регулярные выражения эквивалентны автоматам. По регулярным выражениям можно достаточно легко строить $\epsilon$-НКА, если отдельно рассмотреть все возможные способы задания языка, и дальше рекурсивно. То есть, $A+B$ выражается, если последовательно записать автоматы $A$ и $B$, и перегнать терминалы $A$ в стартовую вершину для $B$. Остальные каким-то похожим образом. 57 | 58 | Вот теперь совсем последний шаг --- надо показать, что любой ДКА можно задать регулярным выражением. Введем $L_i(v, u)$ --- 59 | регулярное выражение, которое задает все строки, по которым можно пройти из $v$ в $u$ в ДКА, используя первые $i$ ребер. Изначально это какие-то пустые регулярки. Потом добавляем ребро $(x, y, c)$. Тогда $L_{i+1}(v, u) = L_i(v, u) \cup \{L_i(v, x) + c + \{L_i(y, x) + c\}^* + L_i(y, u)\}$. 60 | 61 | \paragraph{Лемма о накачке.} Для любого регулярного языка $L$ существует такое $n$, что для всех строк $|s| \ge n$ верно, $s = uvw$, $|uv| \le n$, $\forall k \ge 0\ s'=uv^kw \in L$. Доказательство такое: посмотрим на ДКА и возьмем $n$, равное числу вершин. Тогда для длинных строк их путь будет содержать цикл. Этот цикл как раз и соответствует строке $v$. Это значит, что любая достаточно длинная строка имеет циклическую структуру внутри. 62 | 63 | 64 | 65 | \end{document} -------------------------------------------------------------------------------- /tex_files/lec_35_1905.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 19.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Минимизация ДКА.} Два автомата изоморфны, если они изоморфны как графы с буквами на ребрах и с учетом терминальных вершин. Мы хотим найти автомат минимального размера, который будет принимать тот же язык, что и заданный автомат. 49 | 50 | Выделим классы эквивалентности по вершинам автомата. А именно, каждой вершине в соответствие ставим множество строк, которые из нее читаются. Мы покажем, что автомат, где вершинами будут классы эквивалентности, минимален. 51 | 52 | \textit{Замечание.} Классы будут либо терминальными, либо нет, в зависимости от того, принадлежит ли классу пустая строка. 53 | 54 | Почему такой построить можно? Потому что если склеить вершины с одинаковым множеством читаемых строк, то множество строк, принимаемых автоматом, не изменится. Поэтому алгоритм построения такого автомата будет тривиальным --- нам надо просто объединять вершины с одинаковым множеством строк. 55 | 56 | Пусть есть автомат меньшего размера, принимающий такой же язык. Для представителя каждого класса эквивалентности выберем строку, которая в него ведет. Тогда какая-то пара строк будет вести в одну и ту же вершину минимального автомата. Язык, соответствующий этой вершине, не совпадает хотя бы с одним из языков классов эквивалентности. 57 | 58 | Если автомат был ациклическим, то нам надо взять вершины в порядке топологической сортировки, после чего надо вершине ставить в соответствии множество $terminal, class(go_{c_1}), class(go_{c_2}), \ldots, class(go_{c_n})$. Тогда достаточно просто смотреть, был ли класс с таким множеством раньше. Для этого можно воспользоваться хэш-таблицей, и получить алгоритм сложностью $O(m)$. 59 | 60 | \paragraph{Алгоритм Хопкрофта.} Теперь наш автомат может иметь циклы. Мы будем наращивать классы постепенно. А именно, если вершины относятся к разным промежуточным классам, то они уже точно разные, а вершины внутри одного класса еще могут быть одинаковыми. Изначально классы определяются терминальностью вершины. Потом можно брать и определять новый класс с помощью хэша от классов вершин-потомков. Тогда надо делать операцию, пока классы меняются. Почему этого хватает? Потому что если две вершины были разными, и отличались строкой $L$, и $|L|$ было минимальным из возможных, то тогда на каждом шаге $1, 2, \ldots |L|$ одна вершина будет менять свой класс. Работать алгоритм будет за $O(nm \sigma)$, но это наш медленный алгоритм. 61 | 62 | Теперь, чтобы улучшить алгоритм, воспользуемся идеей о классах-сплиттерах. Если нашим промежуточным классом мы разбили другой класс по символу $c$ (то есть, если для какого-то $A$ верно, что из него есть переход по $c$ и в класс $B$, и вне класса $B$), то тогда для его непересекающихся подклассов $B_1, B_2$ верно, что в дальнейшем можно будет разбивать только по одному из них. Доказательство из теории множеств --- если мы уже разбили по двум классам, то по информации $x \stackrel{?}{\in} B,\ x \stackrel{?}{\in} B_1$ однозначно достраивается $x \stackrel{?}{\in} B_2$ 63 | 64 | Кроме того, число разбиений линейно --- если взять сумму $|C| - 1$ по всем классам, то каждое разбиение уменьшает эту сумму на 1. Поскольку эта величина неотрицательна и изначально $O(m)$, то и количество ненулевых разбиений будет линейно. А количество нулевых разбиений не более чем в два раза превышает количество ненулевых. 65 | 66 | Ну тогда достаточно сохранить обратные переходы в автомате, рассматривать классы в порядке очереди, а при разбиении класса на два класса поменьше можно добавить в очередь только меньший из $A_1, A_2$. Тогда рассматривать конкретный обратный переход в автомате мы будем не более, чем $O(\log m)$ раз, а значит суммарное время работы будет $O(m \Sigma \log m)$. Тут, правда, важно, что каждое разбиение должно быть проведено за $O(|B| + \sum |A_1|)$, где $B$ --- это класс, по которому мы разбиваем, а $A_1$ --- это меньший из двух непустых классов разбиения (тут важно, что сумма $A_1$ оценивается как $O(m \Sigma \log m)$ только если $|A_1| < |A_2|$), но это не очень сложно сделать, если поддерживать всякие счетчики, и при перенаправлении указателей для разбиения делать новый класс меньшим из двух. 67 | 68 | 69 | \end{document} 70 | -------------------------------------------------------------------------------- /tex_files/lec_36_2605.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 26.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Машина Тьюринга.} МТ --- это абстрактная модель вычислений, которая состоит из каретки и бесконечной ленты, по которой каретка будет двигаться. Программа для МТ --- это автомат, который по состоянию и букве на позиции каретки говорит, что должна сделать каретка и в какое состояние должен перейти алгоритм. То есть, написать что-то в текущую клетку, сдвинуть каретку на позицию вбок. Будем считать, что $P$ --- это такой класс задач, для которых ответ бинарен, и для любого ввода алгоритм для МТ работает за полиномиальное время от размера ввода. Соответственно, для них автомат тоже имеет полиномиальный размер. 49 | 50 | \paragraph{NP-полнота.} Введем несколько задач с бинарным ответом (то есть да/нет), которые мы будем хотеть решать: 51 | 52 | \begin{itemize} 53 | \item Lin solver --- решение системы линейных уравнений (Полиномиальна --- алгоритм Гаусса) 54 | \item SAT --- Задача о булевой разрешимости 55 | \item CNF-SAT --- SAT, который задается набором конъюнктов, каждый конъюнктов внутри состоит из скольки-то дизъюнктов. 56 | \item Suset-sum --- задача о рюкзаке 57 | \item k-Clique --- задача о поиске клики размера $k$. 58 | \item Ham --- задача о поиске Гамильтонова цикла/пути. 59 | \item Euler --- Задача о поиске эйлерова цикла/пути (опять-таки, полиномиальна) 60 | \end{itemize} 61 | 62 | Эти задачи интересны тем, что полиномиального алгоритма решения для них пока что нет (ну кроме тех, про которые я написал обратное), но зато есть полиномиальный способ проверить, верен ли положительный ответ (сертификат). Для $P$-задач алгоритм проверки совпадает с решением --- само условие задачи уже является своим сертификатом. 63 | 64 | Будем считать, что задачи $NP$ (non-deterministic polynomial) --- это такие задачи, которые разрешимы на недетерминированной машине Тьюринга. В недетерминированной машине Тьюринга надо делать одну из операций, записанных в ячейке. Раньше в ячейке была только одна команда, а теперь может быть несколько --- мы сами можем выбрать, какое нас интересует. Задача разрешима на такой машине, если все пути в дереве разбора имеют полиномиальный размер. Например, в задаче Subset-sum можно сделать автомат вида <<полное бинарное дерево>>, глубина которого будет полиномиальна, а листов будет $2^n$. Тогда сертификатом будет просто путь в этом дереве. 65 | 66 | Если у задачи есть возможность полиномиально проверить отрицательный ответ, то она принадлежит классу $co-NP$. 67 | 68 | Задача называется NP-трудной, если она хотя бы так же трудна, как и любая другая задача из $NP$. 69 | 70 | Что такое <<так же трудна>>? Задача $A$ сводится к задаче $B$, мы должны предъявить полиномиальный алгоритм, который преобразует задачу $A$ в задачу $B$ (переводит вход $А$ в вход $B$, решение $B$ в решение $A$). То есть, задача называется NP-трудной, если ее полиномиальное решение автоматически решит все задачи из $NP$. 71 | 72 | Задача называется NP-полной, если она и $NP$ и $NP$-трудная. 73 | 74 | \paragraph{Теорема Кука.} Любая задача из $NP$ может быть записана в виде CNF-SAT. По любой задаче из NP мы знаем ее дерево решения для недетерминированной машины Тьюринга. Кроме того, у нас есть детерменированная МТ, которая умеет проверять сертификат. Рассмотрим эту МТ. Мы можем взять все состояния во все моменты времени как переменные, все положения каретки во все моменты времени как переменные, все символы на ленте во все моменты времени как переменные. Тогда в каждый момент времени для нас эти параметры задают булевый вектор. 75 | 76 | \begin{itemize} 77 | \item В булевом векторе для состояния, положения и символов одной позиции должно быть ровно по одной единице. 78 | \item Значения для всех символов в момент времени 0 должны совпадать со стартовыми значениями, кроме тех позиций, которые соответствуют сертификату --- они могут быть любыми. 79 | \item Поскольку у нас везде по одному переходу, то нам надо построить граф имликаций. 80 | \item Кроме того, надо сделать условие, что символ меняется только под кареткой. Это тоже какие-то импликации 81 | \end{itemize} 82 | 83 | Схема будет иметь полиномиальный размер. Решение схемы явно задаст стартовые переменные, которые выдадут сертификат-решение, поэтому решение схемы решит и задачу. 84 | 85 | В целом, подробное доказательство гораздо сложнее, но тут уже можно додумать, а громоздких записей нет. 86 | 87 | \end{document} 88 | -------------------------------------------------------------------------------- /tex_files/lec_37_2805.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 28.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Быстрое возведение числа в степень.} $a^n = a^{2^{p_1} + 2^{p_2} + 2^{p_k}}$. $(a^n)^2 = a^{2^{p_1 + 1} + 2^{p_2 + 1} + 2^{p_k + 1}}$. Тогда чтобы получить значение $a^n$ можно разложить $n$ на степени двойки, а дальше работать с ним как с вектором степеней: мы можем либо приписать в конец 0 (то есть умножить на $a$) или прибавить ко всем числам 1 (то есть возвести в квадрат). Можно заметить, что такими операциями получится получить любую степень за логарифмическое время. 49 | 50 | 51 | \paragraph{Диофантовы уравнения.} Дано уравнение $ax + by = c$. Сначала разделим все на $gcd(a, b)$, получим $a'x + b'y = c'$, где $gcd(a', b') = 1$. Тогда существует решение уравнения $a'x + b'y = 1$, которое находится расширенным алгоритмом Евклида, а дальше корни можно получить умножением на $c'$. 52 | 53 | Алгоритм Евклида для поиска $gcd$ использует то, что если $a > b$ $gcd(a, b) = d$, то $a = dx,\ b = dy,\ a - b = d(x - y), gcd(a, b) = gcd(b, a - b)$. Ну тогда можно сжать много операций вычитания подряд одним взятием остатка. Брать остаток можно не более $O(\log C)$ раз --- если $a > 2b$, то $b$ явно уменьшилось в два раза, а если $a < 2b$, то $a - b < \frac{a}{2} < b$. 54 | 55 | Теперь рассмотрим расширенный алгоритм Евклида. Он будет возвращать решение уравнения $ax + by = 1$. Мы будем пользоваться тем, что точка останова для нашего алгоритма это $a = 1,\ b = 0$, тогда $x = 1, y = 0$. Тогда можно явно предъявить пересчет рекурсии: 56 | 57 | $$bx + (a\ mod\ b)y = 1$$ 58 | 59 | $$bx + (a - \lfloor \frac{a}{b} \rfloor b)y = 1$$ 60 | 61 | $$ay + b (x - \lfloor \frac{a}{b} \rfloor y) =1$$ 62 | 63 | Тогда $x' = y,\ y' = x - \lfloor \frac{a}{b} \rfloor y$. 64 | 65 | \paragraph{КТО.} Если у нас есть набор взаимно простых чисел, которые используются как модули, то остаток по каждому из этих модулей задает число. Иначе говоря, если взять число, меньшее чем НОК модулей, то для него существует единственное представление через вектор остатков. Понятно, что размеры множества векторов и чисел меньших НОК одинаковый, для любого числа есть представление в виде вектора. Значит нам важно только то, что для любого вектора остатков существует число, у которого именно такое представление. 66 | 67 | Построим итеративно это число. $x \equiv r_i \pmod{m_i}$. Тогда $m_1 \cdot X - m_2 \cdot Y = r_2 - r_1$. Если разность остатков равна нулю, то это просто задает нам один общий остаток по произведению модулей, а иначе мы можем найти решение, которое, опять же, задает нам остаток по произведению двух модулей. 68 | 69 | \paragraph{Факторизация числа.} Число можно представить в виде произведения простых чисел, каждое из которых задано в какой-то степени. 70 | 71 | Факторизовать одно число можно за $O(\sqrt{n})$, потому что не бывает двух простых делителей числа, больших чем $\sqrt{n}$ (иначе их произведение больше чем $n$). Тогда можно пройтись по первым $O(\sqrt{n})$ чисел, и делить на них основное, чтобы узнать показатель степени. Это работает за $O(\sqrt{n} + \log n) = O(\sqrt{n})$. 72 | 73 | \paragraph{Решето Эратосфена.} Часто нам хочется сделать предподсчет, чтобы потом быстро факторизовать числа от 1 до $n$. Для этого хочется запомнить для всех чисел их минимальный простой делитель. Тогда факторизовать можно будет за $O(\log n)$. 74 | 75 | Можно, например, перебрать делители, перебрать второй множитель от $1$ до $\frac{n}{x}$, и проставить соответствующие пометки в клетках, которые получатся как произведение. Это будет работать за $O(n \rangesum{i=1}{n}\frac{1}{i}) = O(n \log n)$ (очень грубая оценка, можно оценить как сумму обратных простых как $O(n\log \log n)$) 76 | 77 | Давайте сделаем решето за линейное время. Мы хотим теперь ставить пометки для каждого числа $m = x \cdot d$ только один раз --- когда $x$ это его минимальный простой делитель. Тогда, если мы для текущего числа $d$ поставим пометку для всех чисел $m$, которые получаются домножением на $x \le min\_divisor(d)$, то $x$ будет минимальным простым делителем $m$, поэтому мы каждое $m$ рассмотрим всего 1 раз. 78 | 79 | \end{document} 80 | -------------------------------------------------------------------------------- /tex_files/lec_38_0206.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 02.06} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Ро-метод Полларда.} 49 | 50 | $$\mathbb{Z}_n = \{0, 1, \ldots, n - 1\}$$ 51 | $$\mathbb{Z}_n^+ = \{1, 2, \ldots, n - 1\}$$ 52 | $$\mathbb{Z}_n^* = \{z \in \mathbb{Z}_n^+\,:\,gcd(z, n) = 1\}$$ 53 | 54 | Заметим, что для каждого числа количество чисел, не взаимно простых с составным $n$, хотя бы $O(\sqrt{n})$. Тогда можно было бы выбрать много случайных чисел и проверить, что $gcd(z, n) > 1$. Для каждого такого числа вероятность найти делитель будет $\frac{\sqrt{n}}{n} = \frac{1}{\sqrt{n}}$. Нам не хватает такой точности. 55 | 56 | Построим функциональный граф для какой-то псевдослучайной функции $g$ (чаще всего $g(x) = x^2 + 1$ по модулю $n$) на остатках. Также навесим дополнительное требование на $g$, чтобы она сохранила остатки (то есть $g(x)\ mod\ a = g(x\ mod\ a)\ mod\ a$, наша функция этому удовлетворяет). Заметим, что в нем произвольный бесконечный путь будет выглядеть как буква $\rho$ --- сначала какой-то период, а потом цикл. С учетом случайности функции и парадокса дней рождения в этой букве $\rho$ будет $\sqrt{n}$ вершин. 57 | 58 | Пока что мы еще ничего не выиграли, но осталось совсем немного. Возьмем и мысленно сделаем функциональные графы по всем остаткам меньше $n$ (назовем их $a$). При этом мы явно будем генерировать только путь в функциональном графе для числа $n$. Поскольку у составного $n$ был делитель меньше, чем $2\sqrt{n}$, то в каком-то функциональном графе мы зациклимся за $O(\sqrt[4]{n})$ шагов. Если мы возьмем все пары $(x_i, x_{2i})$, то тогда они за линейное время относительно размера буквы $\rho$ будут указывать на одинаковую вершину. А это будет значить, что $|x_i - x_{2i}| \equiv 0 \pmod{a}$. Тогда если $a$ было делителем $n$, то $gcd(|x_i - x_{2i}|, n) > 1$. Тогда мы нашли какой-то делитель и можно раскладывать рекурсивно. 59 | 60 | \paragraph{Алгоритм Миллера-Рабина.} Создадим тест-проверку на $a^{n-1} \equiv 1 \pmod{n}$. Если это было верно для всех $a$ от 1 до $n - 1$, то число $n$ было простым, потому что тогда оно было взаимно простым со всеми $a < n$. Мы хотим брать случайные числа $a$, при этом сделать немного итераций. Это называется тестом Ферма. 61 | 62 | Просто брать случайные $a$ нельзя --- есть числа Кармайкла, которые работают в качестве контртеста. Их какое-то полиномиальное количество, хоть и не очень много. 63 | 64 | Сделаем новый тест: $a^2 \equiv 1 \pmod{n}, a \neq 1, a \neq -1$, таких чисел не бывает для простых $n$ (потому что это будет означать что $(a - 1)(a + 1) \equiv 0 \pmod{n}$) 65 | 66 | Рассмотрим $n - 1 = 2^s \cdot k, k \equiv 1 \pmod{2}$. 67 | 68 | Сделаем $A(x) = \{x^k, x^{2k}, x^{4k}, \ldots, x^{n - 1}\}$. Тогда если у нас есть пара соседей $(d, 1), d \neq 1, d \neq -1$, то тогда наш второй тест провалился --- $n$ не простое. Если последним элементом последовательности было число $d \neq 1$, то провалился тест Ферма --- число составное. Назовем свидетелями такие $x$, для которых один из этих тестов выполнился, остальных назовем лжецами. Мы хотим показать, что при случайном выборе $x$-ов, вероятность получить лжеца будет не выше $\frac{1}{2}$. 69 | 70 | Тогда $x \in \mathbb{Z}_n^+$, $\mathbb{Z}_n^+ = W \cup L$. 71 | А еще запомним, что $\mathbb{Z}_n^*$ --- группа. 72 | 73 | Пусть наше число не было числом Кармайкла. Тогда $\exists x \in \mathbb{Z}_n^*\,:\,x^{n-1} \not\equiv 1 \pmod{n}$. Тогда можно взять подгруппу $B = \{z \in \mathbb{Z}_n^* : z^{n-1} \equiv 1\}$ (она содержит единицу, ) 74 | 75 | 76 | 77 | План: Хотим показать, что $L \subseteq B \subseteq \mathbb{Z}_n^*$ 78 | 79 | Автор сломался понять доказательство, возможно затехает его позже. 80 | 81 | \end{document} 82 | -------------------------------------------------------------------------------- /tex_files/lec_39_0906.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Лекция АиСД 09.06} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Задача шифрования.} В общем задача выглядит так: есть Алиса и Боб, которые хотят передавать друг другу информацию таким образом, чтобы их сообщение можно было перехватить, но перехвативший человек не понял бы, что в нем написано. Дальше будем считать, что канал между Алисой и Бобом прослушивается Евой. В принципе, Евой может быть кто угодно, потому что каналы публичные. Причем, даже если Ева прочитает и расшифрует сообщение, Алиса с Бобом даже не узнают про это. 49 | 50 | \paragraph{Схема RSA.} Пусть у Алисы и Боба было по два объекта: публичный и приватный ключ. Ключ --- это просто какой-то шифровальный объект. При этом ключи взаимообратимы, но для каждого из них по отдельности найти обратную функцию сложно, то есть $M = private(public(M)) = public(private(M))$. Если все участники знают публичные ключи, то обмен можно провести таким образом: Алиса произносит $public_B(M)$, тогда Боб делает $private_B(public_B(M)) = M$. 51 | 52 | Факты для RSA: 53 | \begin{itemize} 54 | \item $\forall a,n:\ a^{\phi(n)} \equiv 1 \pmod{n}$ 55 | \item $(a, b) = 1 \rightarrow \phi(ab) = \phi(a)\phi(b)$ 56 | \item Можно проверить число на простоту за $O(\log^k n)$ 57 | \item Нельзя посчитать факторизацию $n$ за $O(\log^k n)$. Этот факт не доказан человечеством. 58 | \end{itemize} 59 | 60 | 61 | Зафиксируем два простых ключа $p_1, p_2$. Их произведение равно $n$. Мы знаем, чему равно $\phi(n)$ --- это $(p_1 - 1)(p_2 - 1)$. При этому быстро посчитать $\phi(n)$ нельзя по факту 4. 62 | 63 | Нашим публичным ключом будет пара $(e, n)$, приватным ключом будет пара $(d, n)$. $e$ и $d$ --- это такие числа, что $ed \equiv 1 \pmod{\phi(n)}$. Тогда $M^{ed} = M$. Тогда Алиса сначала фиксирует какое-то $e$, взаимно простое с $\phi(n)$. Тогда Алиса может решить диофантово уравнение $ed + \phi(n)m = 1$, получая $d$. 64 | 65 | Теперь пусть все знают $e$. Тогда Алиса посылает $M^e$, Боб делает $M^ed = M^{\phi(n)k + 1} = M$. 66 | 67 | \paragraph{Man in the middle и authority.} На самом деле, описанный выше не работает, если у нам есть Мэллори, которая читает и модифицирует канал связи между Алисой и Бобом. Мэллори может выдать им свои публичные ключи в качестве публичного ключа друг друга. Тогда Мэллори будет явно читать весь канал между Алисой и Бобом, причем поскольку она знает публичные ключи Алисы и Боба, она может отправлять им что угодно. 68 | 69 | Таким образом, мы хотим решить следующую задачу: получить публичный ключ, которому можно доверять. 70 | 71 | Мы предположим, что у нас есть добрый Трент, которому все стороны доверяют, и публичный ключ которого известен всем. Тогда все могут сообщить Тренту свои публичные ключи и спросить у Трента чужие публичные ключи. 72 | 73 | \paragraph{Цифровая подпись.} Для того, чтобы все точно верили, что сообщение отправляет именно Трент, он может отправить пару $(M, private(M))$. Это называется цифровой подписью Трента. Теперь наши участники запрашивают сертификат у Трента, а Трент в качестве сертификата выдает Алисе свою цифровую подпись для этого ключа. То есть теперь Алиса может отправлять свой публичный ключ, представляясь Алисой, которую одобрил Трент. 74 | 75 | 76 | \end{document} 77 | -------------------------------------------------------------------------------- /tex_files/sem_01_2210.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Макоян Артем, ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Семинар по АиСД 22.10} 65 | 66 | \begin{document} 67 | 68 | 69 | \large 70 | 71 | t(n, input) - время работы алгоритмы при входных данных input размера n. Тогда время работы алгоритма $t(n) = max_{input} t(n, input)$. 72 | 73 | $t(n) = O(f(n)) \Leftrightarrow \exists c > 0, \; N > 0 : \forall n > N \; t(n) \leq c \cdot f(n)$. 74 | 75 | $t(n) = o(f(n)) \Leftrightarrow \forall c > 0, \exists N : \forall n > N \; t(n) \leq c \cdot f(n)$. 76 | 77 | $t(n) = \Omega(f(n)) \Leftrightarrow \exists c > 0, \; \forall N, \; \exists n > N, \; input : t(n, input) \geq c \cdot f(n) $. 78 | 79 | $t(n) = \omega(f(n)) \Leftrightarrow \forall c > 0, \; \forall N, \; \exists n > N, \; input : t(n, input) \geq c \cdot f(n) $. 80 | 81 | $t(n) = \theta(f(n)) \Leftrightarrow t(n) = \Omega(f(n)), \; t(n) = O(f(n))$. 82 | 83 | Алгоритм является \tu{полиномиальным}, если $t(input) = O(\abs{input}^k)$. $\abs{input}$ - битовая длина. 84 | 85 | \tu{Сильно полиномиальный алгоритм} - $t(n) = O(Poly(n))$ - string-poly 86 | 87 | \tu{Слабо полиномиальный алгоритм} - $O(Poly(n, \log{C}))$ - weak-poly 88 | 89 | \tu{Псевдо полиномиальный алгоритм} - $O(Poly(n, C))$ - pseudo-poly 90 | 91 | 92 | \end{document} -------------------------------------------------------------------------------- /tex_files/sem_04_1211.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | 3 | \usepackage[top=0.6in, bottom=0.75in, left=0.625in, right=0.625in]{geometry} 4 | \usepackage{amsmath,amsthm,amssymb,hyperref} 5 | \usepackage[utf8x]{inputenc} 6 | \usepackage[russianb]{babel} 7 | \usepackage{hyperref} 8 | % \usepackage{minted} 9 | \usepackage{color} 10 | \usepackage{fancyhdr} 11 | 12 | 13 | \newcommand{\R}{\mathbb{R}} 14 | \newcommand{\Z}{\mathbb{Z}} 15 | \newcommand{\N}{\mathbb{N}} 16 | \newcommand{\Q}{\mathbb{Q}} 17 | \newcommand{\tu}[1]{\underline{#1}} 18 | \newcommand{\tb}[1]{\textbf{#1}} 19 | \newcommand{\ti}[1]{\textit{#1}} 20 | \newcommand{\aliq}{\mathrel{\raisebox{-0.5ex}{\vdots}}} 21 | \newcommand{\mylim}[2]{\lim_{#1 \to #2}} 22 | \newcommand{\abs}[1]{\left|{#1}\right|} 23 | \newcommand{\brackets}[1]{\left({#1}\right)} 24 | \newcommand{\sqbrackets}[1]{\left[{#1}\right]} 25 | 26 | \newenvironment{theorem}[2][Theorem]{\begin{trivlist} 27 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 28 | \newenvironment{lemma}[2][Lemma]{\begin{trivlist} 29 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 30 | \newenvironment{claim}[2][Claim]{\begin{trivlist} 31 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 32 | \newenvironment{problem}[2][Problem]{\begin{trivlist} 33 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 34 | \newenvironment{proposition}[2][Proposition]{\begin{trivlist} 35 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 36 | \newenvironment{corollary}[2][Corollary]{\begin{trivlist} 37 | \item[\hskip \labelsep {\bfseries #1}\hskip \labelsep {\bfseries #2.}]}{\end{trivlist}} 38 | 39 | \newenvironment{solution}{\begin{proof}[Solution]}{\end{proof}} 40 | 41 | \makeatletter 42 | \newenvironment{sqcases}{% 43 | \matrix@check\sqcases\env@sqcases 44 | }{% 45 | \endarray\right.% 46 | } 47 | \def\env@sqcases{% 48 | \let\@ifnextchar\new@ifnextchar 49 | \left\lbrack 50 | \def\arraystretch{1.2}% 51 | \array{@{}l@{\quad}l@{}}% 52 | } 53 | \makeatother 54 | 55 | \ifx\pdfoutput\undefined 56 | \usepackage{graphicx} 57 | \else 58 | \usepackage[pdftex]{graphicx} 59 | \fi 60 | 61 | \pagestyle{fancy} 62 | \fancyhf{} 63 | \fancyhead[LE,RO]{Макоян Артем, ПМИ 191-1, @MakArtKar, \href{http://github.com/MakArtKar}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/MakArtKar}{\textcolor{blue}{codeforces}}, \href{vk.com/makartkar}{\textcolor{blue}{vk}}} 64 | \fancyhead[RE,LO]{Семинар по АиСД 12.11} 65 | 66 | \begin{document} 67 | 68 | 69 | \large 70 | 71 | \begin{itemize} 72 | \item unit test (обычные, запускаем просто тесты) 73 | \item integration (разные компоненты программы нормально живут вместе) 74 | \item prod (тестирование от самого начала до конца) 75 | \end{itemize} 76 | 77 | % Однажды Mike решил добавить prod test: "зайди на страницу tourist и проверь, что он Гена Короткевич, если что-то пошло не так, то перезапусти codeforces". Во время одного из раундов он решил уменьшить дополнительную нагрузку и запретил смотреть профили. Раунд был не рейтинговым. 78 | 79 | % Язык C++ заботливо разложил грабли на каждом углу, а потом вас завели в этот темный амбар, где вокруг вас не просто темнота, а прямо Vantablack. 80 | 81 | \end{document} -------------------------------------------------------------------------------- /tex_files/sem_12_1712.tex: -------------------------------------------------------------------------------- 1 | \documentclass{article} 2 | \usepackage[T2A]{fontenc} 3 | \usepackage[utf8]{inputenc} 4 | \usepackage[russian]{babel} 5 | \usepackage[pdftex]{graphicx} 6 | \usepackage{amsfonts} 7 | \usepackage{amsmath} 8 | \usepackage{fancyhdr} 9 | 10 | \author{Иваник Даниил} 11 | \title{Семинар + лекция} 12 | 13 | \pagestyle{fancy} 14 | \fancyhf{} 15 | \fancyhead[LE,RO]{Иваник Даниил} 16 | \fancyhead[RE,LO]{Семинар АиСД 17.12} 17 | 18 | \begin{document} 19 | Вот нам split и merge ДД рассказали. 20 | 21 | Insert 22 | Генерируем вершину с нашим ключом и случайным приоритетом. Сплитим дерево по x, который хочется вставить. Мёрджим левое поддерево с вершиной, а потом полученное с правым поддеревом. 23 | 24 | Erase 25 | Сплитим по x + 1, потом левое поддерево по x. Затем мёрджим два крайних дерева. 26 | 27 | Обсудим, как удалить элемент, если нельзя инкрементировать, а можно только сравнивать. 28 | 29 | 1 способ. Пусть удаляемый ключ - A. Найдём следующий ключ в ДД - B. Сплитим по B, потом левое по A. Мёрджим два крайних дерева. 30 | 31 | 2 способ. Делаем два сплита (первый отправляет равные ключи влево, второй отправляет равные ключи вправо). Тогда, с помощью таких операций можно выразить удаление. 32 | 33 | Ещё один способ вставки (на практике быстрый) 34 | Спускаемся по бин дереву особо не задумываясь. Идём вниз по бин дереву, пока не нарушаются условия для приоритетов. Когда условия нарушилось, берём это поддерево, сплитим его и ставим нашу вершину на это место, а левыми и правыми сыновьями делаем расспличенныедеревья. 35 | 36 | Ещё один способ удаления (аналогичный) 37 | Ищем элемент. Мёрджим два поддерева дерева, а потом просто подвешиваем полученное дерево на место исходной вершины. 38 | 39 | Подсчёт k-ой порядковую статистику. Для каждой вершины храним размер поддерева. Идём по дереву и смотрим на размер левого поддерева. Если он больше, чем текущий счётчик, то идём в левое поддерево, если равен, то мы уже там где надо, иначе уменьшаем счётчик на размер левого поддерева + 1 и идём вправо. Изначально счётчик равен k. 40 | 41 | 42 | По неявному ключу. 43 | Хотим структуру: массив, к индексам которого можно обращаться за log и вставлять в середину за log. 44 | 45 | Переделаем split: 46 | Делаем разрезы не по ключу, а по количеству (совметим идеи split и k-ой порядковой статистики). Теперь мы не пользуемся тем, что ключи отсортированны и мы можем ключи использовать как какой-нибудь мусор. 47 | 48 | Итерироваться по такому массиву можно за линию (каждый переход по ребру туда и обратно занимает одну операцию). 49 | 50 | Вращение в массиве: 51 | Вырезаем splitом первые k элементов, а потом меняем два поддерева местами и мёрджим. 52 | 53 | Ещё всякие приколы: 54 | Умеем находить максимум на отрезке. В вершине будем хранить значение максимума в поддереве. Выспличиваем наш подотрезок и смотрим на значение в корне. 55 | 56 | Умеем зеркально отражать подотрезки. Будем в каждой вершине хранить модификаторы и если надо - будем их проталкивать вниз. Когда разворачиваем поддерево вершины - просто говорим, что его модификатор = 1. Теперь, когда хотим проталкивать делаем вот что: убираем флажок в нашей вершине меняем ссылки на левого и правого сына и ксорим с единицей флажок детей. Теперь, вершина - абсолютно нормальная. 57 | 58 | Построение декартача за линию, когда x уже отсорчены. 59 | 60 | Пойдём слево направо. Когда вставляем новую вершину идём снизу вверх от самой большой вершины дерева к корню и смотрим, в какой момент мы можем вставить нашу вершину. Мы ее вставляем как корень соответствующего поддерева, а потом переподвешиваем её туда, куда нужно. Аммортизированно - линия. Потенциал - длина правого пути (упражнение))). При этом правый путь надо хранить стэком. 61 | 62 | interleave (как merge, только ключи первого дерева не обязательно меньше). 63 | Тут трэш начался)) Если коротко, то мы огкусываем от первого дерева все элементы, которые меньше минимума во втором, потом отрезаем от второго дерева, ну и продолжаем так, пока оба дерева не пропадут. А потом просто мёрджишь по порядку. 64 | 65 | \end{document} -------------------------------------------------------------------------------- /tex_files/sem_13_1401.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section {Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\mintedparams}{ 32 | % frame=lines 33 | % framesep=2mm, 34 | % baselinestretch=1.2, 35 | % bgcolor=LightGray 36 | } 37 | 38 | \pagestyle{fancy} 39 | \fancyhf{} 40 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 41 | \fancyhead[RE,LO]{Семинар 14.01} 42 | 43 | \begin{document} 44 | 45 | \paragraph{Splay tree.} 46 | 47 | Уже пройденные способы балансировки для $BST$, которые у нас были, это способы из ДД (четкая структура и ожидаемая глубина) и 2-3 дерева (гарантированная одинаковая глубина для всех вершин). 48 | 49 | Новый способ балансировки --- не напрягаться с балансированием лишний раз, и работать за амортизированное время. 50 | 51 | Основной нашей операцией будет $expose(v)$, которая будет превращать вершину $v$ в корень дерева. Условие $BST$ на дереве сохраняется. Эта операция будет поддерживать два типа поворотов: левый и правый. Поворот вершины $v$ возьмет ребро от $v$ к предку $u$, и его <<повернет>> ~--- если $v$ было левым сыном $u$, то $u$ станет правым сыном $v$. При этом правый сын $v$ станет левым сыном $u$. Другой поворот делается симметрично. Вершина $v$ станет ближе к корню дерева. Если применять повороты к $v$, пока можно, то в итоге $v$ станет корнем. 52 | 53 | $expose$ будет выполняться после каждой операции, и работать за высоту дерева. Более того, поскольку все остальное тоже работает за высоту дерева, то мы будем оценивать только $expose$. 54 | 55 | Каждый раз делать повороты нельзя, потому что будет работать за долго. У нас будет три операции, которые будут поднимать нашу вершину: 56 | \begin{itemize} 57 | \item zig 58 | \item zig-zig 59 | \item zig-zag 60 | \end{itemize} 61 | 62 | \paragraph{zig.} Самая тупая операция --- если мы сын предка, то делаем поворот. Оставшиеся операции будут поднимать нас сразу на 2. 63 | 64 | \paragraph{zig-zig.} Если наш дедушка от нас находится справа-справа или слева-слева, то выполним сначала поворот предка, а потом себя. 65 | 66 | \paragraph{zig-zag.} Иначе мы сначала сделаем поворот себя, а потом поворот предка. 67 | 68 | \textit{Лучше порисовать картинки или погуглить визуализацию, потому что иначе будет очень непонятно, что сейчас произошло.} 69 | 70 | Также можно выразить $split$ и $merge$ через предыдущие операции. 71 | 72 | \paragraph{Потенциал.} Введем $\Phi(t) = \displaystyle \sum_{v \in t} rank(v) = \displaystyle \sum_{v \in t} \log_2 {size(v)}$. Тогда стоимость $expose$ это 73 | 74 | $$\tilde t_e = t_e + \Phi(t') - \Phi(t) \le 3(rank(root) - rank(v)) + 1$$ 75 | 76 | Воспользуемся $rank(root) - rank(v) = (rank(root) - rank(u_1)) + (rank(u_1) - rank(u_2)) + \dots + (rank(u_n) - rank(v))$ и разложим $expose$ на три операции, и покажем, что они тоже оплачиваются потенциалом. 77 | 78 | \end{document} 79 | -------------------------------------------------------------------------------- /tex_files/sem_14_1405.tex: -------------------------------------------------------------------------------- 1 | \documentclass[12pt]{article} 2 | \usepackage[utf8]{inputenc} 3 | \usepackage[russian]{babel} 4 | \usepackage[margin=1.5in,left=1cm,right=1cm, top=2cm,bottom=2cm,bindingoffset=0cm]{geometry} 5 | \usepackage{graphicx} 6 | \usepackage{color} 7 | \usepackage{amssymb} 8 | \usepackage{minted} 9 | \usepackage{hyperref} 10 | \usepackage{amsmath} 11 | \usepackage{fancyhdr} 12 | 13 | 14 | 15 | \title{Title} 16 | \author{Амеличев Константин, ПМИ 191.} 17 | \date{Date} 18 | 19 | \newcommand{\problem}[2]{ 20 | 21 | \section*{Задача #1} 22 | \textbf {Постановка задачи.} {#2} 23 | 24 | \textbf {Решение.} 25 | } 26 | 27 | \newcommand{\limit}[2]{\displaystyle \lim_{#1 \to #2}} 28 | 29 | \newcommand{\rangesum}[2]{\displaystyle \sum_{#1}^{#2}} 30 | 31 | \newcommand{\rangeint}[2]{\displaystyle \int_{#1}^{#2}} 32 | 33 | 34 | \newcommand{\mintedparams}{ 35 | % frame=lines 36 | % framesep=2mm, 37 | % baselinestretch=1.2, 38 | % bgcolor=LightGray 39 | } 40 | 41 | \pagestyle{fancy} 42 | \fancyhf{} 43 | \fancyhead[LE,RO]{Амеличев Константин, ПМИ 191, @kik0s, \href{http://github.com/kik0s}{\textcolor{blue}{github}}, \href{http://codeforces.com/profile/kikos}{\textcolor{blue}{codeforces}}, \href{http://vk.com/i_tried_to_name_myself_kikos}{\textcolor{blue}{vk}}} 44 | \fancyhead[RE,LO]{Семинар АиСД 14.05} 45 | 46 | \begin{document} 47 | 48 | \paragraph{Формальные грамматики и языки.} Обозначим алфавит символов за $\sigma$, а множество конечных строк за $L \subset 2^{\sigma^*}$, где $\sigma^*$ --- это все последовательности конечной длины. 49 | 50 | \paragraph{Регулярные выражения.} Тривиальные регулярные выражения: $\empty$ (пустое множество) $\epsilon$ (пустая строка), $x \in \sigma$. Остальные регулярные выражения определяются рекурсивно относительно них. А именно, мы также разрешаем $A + B$ (последовательная запись), $A | B$ (выбор из двух регулярок), $A*$ (повторение строки из языка $A$ $0, 1, 2, \ldots$ раз) Звездочка еще называется замыканием $Kleene$. 51 | 52 | Например, $\{0|1|2|3\}*+\{0|1|2|3\}$ это множество всех непустых строк из символов $\sigma=\{0, 1, 2, 3\}$. 53 | 54 | \paragraph{Способы задания языков.} Регулярные выражения, ДКА, НКА, $\epsilon$-НКА. Эти способы эквивалентны. Очевидно $L_{\text{ДКА}} \subset L_{\text{НКА}} \subset L_{\text{$\epsilon$-НКА}}$ Вложенность $\epsilon$-НКА в ДКА можно показать, если рассмотреть алгоритм приведения одного автомата в другой. Например, можно выделить все подмножества вершин НКА как отдельные вершины ДКА (то есть, он будет иметь экспоненциальный размер). Тогда переход по ребру --- это то же самое, что взять все вершины подмножества, и объединить переходы по ребрам из них. Еще стоит следить за переходами по пустому символу, потому что вершина сразу задает подмножество вершин, достижимых из нее по $\epsilon$-ребрам. 55 | 56 | 57 | 58 | \end{document} 59 | -------------------------------------------------------------------------------- /union.sh: -------------------------------------------------------------------------------- 1 | cd pdf_files 2 | pdfunite lec_??_????.pdf lectures.pdf 3 | pdfunite sem_??_????.pdf seminars.pdf 4 | cd .. --------------------------------------------------------------------------------