<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=46.183.217.186&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=46.183.217.186&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/46.183.217.186"/>
		<updated>2026-06-22T23:36:52Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54960</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54960"/>
				<updated>2016-06-08T13:57:02Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''Kasai, Arimura, Arikawa, Lee, Park algorithm'') {{---}} алгоритм, позволяющий за линейное время вычислить длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для всех соседних суффиксов строки, отсортированных в лексикографическом порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Введём следующие обозначения:&lt;br /&gt;
* &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} данная строка.&lt;br /&gt;
* &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе.&lt;br /&gt;
* &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; {{---}} [[Суффиксный массив | суффиксный массив]].&lt;br /&gt;
* &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; {{---}} массив, обратный суффиксному, который может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]})&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса строк &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[z]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса соседних строк &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;, то есть &amp;lt;tex&amp;gt;lcp[i] = LCP(S_{Suf[i-1]}, S_{Suf[i]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства LCP==&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact1&lt;br /&gt;
|about= №1&lt;br /&gt;
|statement=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
}}&lt;br /&gt;
Также заметим, что &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{i = x + 1 \ldots z}lcp[i]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact2&lt;br /&gt;
|about= №2&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact3&lt;br /&gt;
|about= №3&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к утверждениям 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;lcp[3] = 2&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;lcp[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;lcp[p]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из [[#fact2 | утверждения №2]]. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из [[#fact1 | утверждения №1]].&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;lcp[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;lcp[q] = LCP(S_{k}, S_{i}) \geqslant lcp[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (по [[#lemma | лемме]]).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (по [[#fact3 | утверждению №3]]).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку длиной &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''')&lt;br /&gt;
    '''int''' n &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos  &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == n - 1&lt;br /&gt;
          lcp[n - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; n '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54959</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54959"/>
				<updated>2016-06-08T13:46:56Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''Kasai, Arimura, Arikawa, Lee, Park algorithm'') {{---}} алгоритм, позволяющий за линейное время вычислить длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для всех соседних циклических сдвигов строки, отсортированных в лексикографическом порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Введём следующие обозначения:&lt;br /&gt;
* &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} данная строка.&lt;br /&gt;
* &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе.&lt;br /&gt;
* &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; {{---}} [[Суффиксный массив | суффиксный массив]].&lt;br /&gt;
* &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; {{---}} массив, обратный суффиксному, который может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]})&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса строк &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[z]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса соседних строк, то есть &amp;lt;tex&amp;gt;lcp[i] = LCP(S_{Suf[i-1]}, S_{Suf[i]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства LCP==&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact1&lt;br /&gt;
|about= №1&lt;br /&gt;
|statement=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
}}&lt;br /&gt;
Также заметим, что &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{i = x + 1 \ldots z}lcp[i]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact2&lt;br /&gt;
|about= №2&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact3&lt;br /&gt;
|about= №3&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;lcp[3] = 2&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;lcp[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;lcp[p]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Лемма&lt;br /&gt;
|id = lemma&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;lcp[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;lcp[q] = LCP(S_{k}, S_{i}) \geqslant lcp[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (по [[#lemma | лемме]]).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (по [[#fact3 | утверждению №3]]).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку длиной &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''')&lt;br /&gt;
    '''int''' n &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos  &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == n - 1&lt;br /&gt;
          lcp[n - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; n '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54958</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54958"/>
				<updated>2016-06-08T11:24:43Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''Kasai, Arimura, Arikawa, Lee, Park algorithm'') {{---}} алгоритм, позволяющий за линейное время вычислить&lt;br /&gt;
длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для соседних циклических сдвигов строки, отсортированных в лексикографическом&lt;br /&gt;
порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Нам даны:&lt;br /&gt;
* Строка &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе.&lt;br /&gt;
* [[Суффиксный массив | Суффиксный массив]] &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Массив, обратный суффиксному,  &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;, который может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Пусть у нас есть массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; строк в суффиксном массиве (&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Suf[i-1]&amp;lt;/tex&amp;gt; соответственно).&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства LCP==&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact1&lt;br /&gt;
|about= №1&lt;br /&gt;
|statement=&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact2&lt;br /&gt;
|about= №2&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|id = fact3&lt;br /&gt;
|about= №3&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;lcp[3] = 2&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;\mathrm{lcp}[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;\mathrm{lcp}[p]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Лемма|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;lcp[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;lcp[q] = LCP(S_{k}, S_{i}) \geqslant lcp[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (по лемме).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (по [[#fact3 | утверждению №3]]).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку длиной &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;, с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''')&lt;br /&gt;
    '''int''' n &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos  &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' n - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == n - 1&lt;br /&gt;
          lcp[n - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; n '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2n&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54951</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54951"/>
				<updated>2016-06-08T10:40:31Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''algorithm of Kasai, Arimura, Arikawa, Lee, Park'') {{---}} алгоритм, позволяющий за линейное время вычислить&lt;br /&gt;
длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для соседних циклических сдвигов строки, отсортированных в лексикографическом&lt;br /&gt;
порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Задана строка &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе. Пусть задан суффиксный массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Для вычисления &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; будем использовать вспомогательный массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; определен как обратный к массиву &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Он может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\mathrm{Height}&amp;lt;/tex&amp;gt; {{---}} массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; строк в суффиксном массиве (&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Suf[i-1]&amp;lt;/tex&amp;gt; соответственно).&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;==&lt;br /&gt;
===Факт №1===&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} это минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №2===&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №3===&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;\mathrm{Height}[3] = 2&amp;lt;/tex&amp;gt; {{---}} это длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;.&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;\mathrm{Height}[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;\mathrm{Height}[p]&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
{{Лемма|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;\mathrm{Height}[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{Height}[q] = LCP(S_{k}, S_{i}) \geqslant \mathrm{Height}[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (из леммы).&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (из факта №3).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; содержит длину наибольшего общего префикса строк &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; в суффиксном массиве.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''')&lt;br /&gt;
    '''int''' len &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos  &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == len - 1&lt;br /&gt;
          lcp[len - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; len '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2N&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54949</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54949"/>
				<updated>2016-06-08T10:28:36Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''algorithm of Kasai, Arimura, Arikawa, Lee, Park'') {{---}} алгоритм, позволяющий за линейное время вычислить&lt;br /&gt;
длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для соседних циклических сдвигов строки, отсортированных в лексикографическом&lt;br /&gt;
порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Задана строка &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе. Пусть задан суффиксный массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Для вычисления &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; будем использовать вспомогательный массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; определен как обратный к массиву &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Он может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\mathrm{Height}&amp;lt;/tex&amp;gt; {{---}} массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; строк в суффиксном массиве (&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Suf[i-1]&amp;lt;/tex&amp;gt; соответственно).&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;==&lt;br /&gt;
===Факт №1===&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} это минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №2===&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №3===&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;\mathrm{Height}[3] = 2&amp;lt;/tex&amp;gt; {{---}} это длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;\mathrm{Height}[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;\mathrm{Height}[p]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Лемма|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;\mathrm{Height}[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{Height}[q] = LCP(S_{k}, S_{i}) \geqslant \mathrm{Height}[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (из леммы)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (из факта №3).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; содержит длину наибольшего общего префикса строк &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; в суффиксном массиве.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''')&lt;br /&gt;
    '''int''' len &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos  &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == len - 1&lt;br /&gt;
          lcp[len - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; len '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2N&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54948</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54948"/>
				<updated>2016-06-08T10:24:03Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''algorithm of Kasai, Arimura, Arikawa, Lee, Park'') {{---}} алгоритм, позволяющий за линейное время вычислить&lt;br /&gt;
длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для соседних циклических сдвигов строки, отсортированных в лексикографическом&lt;br /&gt;
порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Задана строка &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе. Пусть задан суффиксный массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Для вычисления &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; будем использовать вспомогательный массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; определен как обратный к массиву &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Он может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\mathrm{Height}&amp;lt;/tex&amp;gt; {{---}} массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; строк в суффиксном массиве (&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Suf[i-1]&amp;lt;/tex&amp;gt; соответственно).&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;==&lt;br /&gt;
===Факт №1===&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} это минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №2===&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №3===&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;\mathrm{Height}[3] = 2&amp;lt;/tex&amp;gt; {{---}} это длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;\mathrm{Height}[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;\mathrm{Height}[p]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Лемма|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;\mathrm{Height}[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{Height}[q] = LCP(S_{k}, S_{i}) \geqslant \mathrm{Height}[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (из леммы)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (из факта №3).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; содержит длину наибольшего общего префикса строк &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; в суффиксном массиве.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''') &amp;lt;font color=green&amp;gt; // str {{---}} исходная строка с добавленным специальным символом $ &amp;lt;/font&amp;gt;&lt;br /&gt;
                                            &amp;lt;font color=green&amp;gt; // suf[] {{---}} суффиксный массив строки str &amp;lt;/font&amp;gt; &lt;br /&gt;
    '''int''' len &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos                            &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == len - 1&lt;br /&gt;
          lcp[len - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; len '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2N&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54947</id>
		<title>Алгоритм Касаи и др.</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%90%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%9A%D0%B0%D1%81%D0%B0%D0%B8_%D0%B8_%D0%B4%D1%80.&amp;diff=54947"/>
				<updated>2016-06-08T10:23:05Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Алгоритм Касаи, Аримуры, Арикавы, Ли, Парка''' (англ. ''algorithm of Kasai, Arimura, Arikawa, Lee, Park'') {{---}} алгоритм, позволяющий за линейное время вычислить&lt;br /&gt;
длину наибольших общих префиксов (англ. ''longest common prefix'', ''LCP'') для соседних циклических сдвигов строки, отсортированных в лексикографическом&lt;br /&gt;
порядке.&lt;br /&gt;
&lt;br /&gt;
==Обозначения==&lt;br /&gt;
Задана строка &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; {{---}} суффикс строки &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, начинающийся в &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ом символе. Пусть задан суффиксный массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Для вычисления &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; будем использовать вспомогательный массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Массив &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; определен как обратный к массиву &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Он может быть получен немедленно, если задан массив &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Если &amp;lt;tex&amp;gt;Suf[k] = i&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;Suf^{-1}[i] = k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\mathrm{Height}&amp;lt;/tex&amp;gt; {{---}} массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt; {{---}} длина наибольшего общего префикса &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; строк в суффиксном массиве (&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;Suf[i-1]&amp;lt;/tex&amp;gt; соответственно).&lt;br /&gt;
&lt;br /&gt;
==Некоторые свойства &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;==&lt;br /&gt;
===Факт №1===&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между двумя суффиксами {{---}} это минимум &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех пар соседних суффиксов между ними в суффиксном массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. То есть &amp;lt;tex&amp;gt;LCP(S_{Suf[x]}, S_{Suf[z]}) = \min\limits_{x &amp;lt; y \leqslant z}LCP(S_{Suf[y - 1]},S_{Suf[y]})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
Отсюда следует, что &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt; больше или равно &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; пары суффиксов, окружающих их.&lt;br /&gt;
&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&amp;lt;tex&amp;gt;LCP(S_{Suf[y - 1]}, S_{Suf[y]}) \geqslant LCP(S_{Suf[x]},S_{Suf[z]}), x &amp;lt; y \leqslant z&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №2===&lt;br /&gt;
Рассмотрим пару суффиксов, соседних в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;. Тогда если их значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; больше &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;, то можно удалить первый символ этих суффиксов и их лексикографический порядок относительно друг друга сохранится. То есть строка &amp;lt;tex&amp;gt;S_{Suf[x] + 1}&amp;lt;/tex&amp;gt; будет идти следом за строкой &amp;lt;tex&amp;gt;S_{Suf[x-1] + 1}&amp;lt;/tex&amp;gt; и останется лексикографически больше нее.&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;Suf^{-1}[Suf[x - 1] + 1] &amp;lt; Suf^{-1}[Suf[x] + 1]&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Факт №3===&lt;br /&gt;
В этом же случае, значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]+1}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]+1}&amp;lt;/tex&amp;gt; на один меньше значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{Suf[x-1]}&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[x]}&amp;lt;/tex&amp;gt;.&amp;lt;br&amp;gt;&lt;br /&gt;
{{Утверждение&lt;br /&gt;
|statement=Если &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]} , S_{Suf[x]} ) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_{Suf[x-1]+1} , S_{Suf[x]+1}) = LCP(S_{Suf[x-1]} , S_{Suf[x]} ) - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
[[Файл:kasai.png|400px|thumb|right|Пояснительная картинка к факту 2 и 3]]&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
Рассмотрим строку &amp;lt;tex&amp;gt;S = aabaaca\$&amp;lt;/tex&amp;gt;. Её суффиксный массив:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Распишем суффиксный массив по столбикам для удобного нахождения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;Suf[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; ||  || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  || &lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
| || || &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; ||  ||  ||  ||  || &lt;br /&gt;
|}&lt;br /&gt;
Строим массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;:&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;4&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;5&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;7&amp;lt;/tex&amp;gt;&lt;br /&gt;
|-&lt;br /&gt;
!&amp;lt;tex&amp;gt;\mathrm{Height}[i]&amp;lt;/tex&amp;gt;&lt;br /&gt;
| &amp;lt;tex&amp;gt;\bot&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt; || &amp;lt;tex&amp;gt;0&amp;lt;/tex&amp;gt;&lt;br /&gt;
|}&lt;br /&gt;
Например &amp;lt;tex&amp;gt;\mathrm{Height}[3] = 2&amp;lt;/tex&amp;gt; {{---}} это длина наибольшего общего префикса &amp;lt;tex&amp;gt;aa&amp;lt;/tex&amp;gt; суффиксов &amp;lt;tex&amp;gt;S_{Suf[2]} = aabaaca\$&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;S_{Suf[3]} = aaca\$&amp;lt;/tex&amp;gt;&lt;br /&gt;
===Вспомогательные утверждения===&lt;br /&gt;
&lt;br /&gt;
Теперь рассмотрим следующую задачу: рассчитать &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf&amp;lt;/tex&amp;gt;, при условии, что значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между &amp;lt;tex&amp;gt;S_{i-1}&amp;lt;/tex&amp;gt; и его соседним суффиксом известны. Для удобства записи пусть &amp;lt;tex&amp;gt;p=Suf^{-1}[i - 1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;q = Suf^{-1}[i]&amp;lt;/tex&amp;gt;. Так же пусть &amp;lt;tex&amp;gt;j - 1 = Suf[p-1]&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k = Suf[q - 1]&amp;lt;/tex&amp;gt;. Проще говоря, мы хотим посчитать &amp;lt;tex&amp;gt;\mathrm{Height}[q]&amp;lt;/tex&amp;gt;, когда задано &amp;lt;tex&amp;gt;\mathrm{Height}[p]&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
{{Лемма|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, тогда &amp;lt;tex&amp;gt;LCP(S_k,S_i) \geqslant LCP(S_j,S_i)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Так как &amp;lt;tex&amp;gt;LCP(S_{j-1},S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;Suf^{-1}[j] &amp;lt; Suf^{-1}[i]&amp;lt;/tex&amp;gt; из факта №2. Так как &amp;lt;tex&amp;gt;Suf^{-1}[j] \leqslant Suf^{-1}[k] = Suf^{-1}[i] - 1&amp;lt;/tex&amp;gt;, имеем &amp;lt;tex&amp;gt;LCP(S_{k} , S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; из факта №1&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема|statement=&lt;br /&gt;
Если &amp;lt;tex&amp;gt;\mathrm{Height}[p] = LCP(S_{j-1}, S_{i-1}) &amp;gt; 1&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{Height}[q] = LCP(S_{k}, S_{i}) \geqslant \mathrm{Height}[p] - 1&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j} , S_{i})&amp;lt;/tex&amp;gt; (из леммы)&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;LCP(S_{j} , S_{i}) = LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; (из факта №3).&lt;br /&gt;
&lt;br /&gt;
Значит, &amp;lt;tex&amp;gt;LCP(S_{k}, S_{i}) \geqslant LCP(S_{j-1}, S_{i-1}) - 1&amp;lt;/tex&amp;gt; &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Представим алгоритм &amp;lt;tex&amp;gt;\mathrm{buildLCP}&amp;lt;/tex&amp;gt; который вычисляет массив &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;, зная суффиксный массив. Исходя из выше написанной теоремы, нам не нужно сравнивать все символы, когда мы вычисляем &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; между суффиксом &amp;lt;tex&amp;gt;S_{i}&amp;lt;/tex&amp;gt; и его соседним суффиксом в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt;. Чтобы вычислить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; всех соседних суффиксов в массиве &amp;lt;tex&amp;gt;Suf^{-1}&amp;lt;/tex&amp;gt; эффективно, будем рассматривать суффиксы по порядку начиная с &amp;lt;tex&amp;gt;S_1&amp;lt;/tex&amp;gt; и заканчивая &amp;lt;tex&amp;gt;S_n&amp;lt;/tex&amp;gt;.&lt;br /&gt;
   &lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Алгоритм принимает на вход строку с добавленным специальным символом &amp;lt;tex&amp;gt;\$&amp;lt;/tex&amp;gt; и суффиксный массив этой строки, и возвращает массив &amp;lt;tex&amp;gt;lcp&amp;lt;/tex&amp;gt;, такой что &amp;lt;tex&amp;gt;lcp[i]&amp;lt;/tex&amp;gt; содержит длину наибольшего общего префикса строк &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;i-1&amp;lt;/tex&amp;gt; в суффиксном массиве.&lt;br /&gt;
 '''int[]''' buildLCP(str: '''string''', suf: '''int[]''') &amp;lt;font color=green&amp;gt; // str {{---}} исходная строка с добавленным специальным символом $ &amp;lt;/font&amp;gt;&lt;br /&gt;
                                            &amp;lt;font color=green&amp;gt; // suf[] {{---}} суффиксный массив строки str &amp;lt;/font&amp;gt; &lt;br /&gt;
    '''int''' len &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; str.length&lt;br /&gt;
    '''int[len]''' lcp&lt;br /&gt;
    '''int[len]''' pos                            &amp;lt;font color=green&amp;gt; // pos[] {{---}} массив, обратный массиву suf &amp;lt;/font&amp;gt;&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       pos[suf[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; i&lt;br /&gt;
    '''int''' k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
    '''for''' i = 0 '''to''' len - 1&lt;br /&gt;
       '''if''' k &amp;gt; 0&lt;br /&gt;
          k--  &lt;br /&gt;
       '''if''' pos[i] == len - 1&lt;br /&gt;
          lcp[len - 1] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; -1&lt;br /&gt;
          k &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; 0&lt;br /&gt;
       '''else'''&lt;br /&gt;
          '''int''' j &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; suf[pos[i] + 1]&lt;br /&gt;
          '''while''' max(i + k, j + k) &amp;lt; len '''and''' str[i + k] == str[j + k]&lt;br /&gt;
             k++&lt;br /&gt;
          lcp[pos[i]] &amp;lt;tex&amp;gt;=&amp;lt;/tex&amp;gt; k&lt;br /&gt;
    '''return''' lcp&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
Таким образом, начиная проверять &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; для текущего суффикса не с первого символа, а с указанного, можно за линейное время построить &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt;. Покажем, что построение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; таким образом действительно требует &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt; времени. Действительно, на каждой итерации текущее значение &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; может быть не более&lt;br /&gt;
чем на единицу меньше предыдущего. Таким образом, значения &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; в сумме могут увеличиться не более, чем на &amp;lt;tex&amp;gt;2N&amp;lt;/tex&amp;gt; (с точностью до константы). Следовательно, алгоритм построит &amp;lt;tex&amp;gt;LCP&amp;lt;/tex&amp;gt; за &amp;lt;tex&amp;gt;O(N)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Алгоритм цифровой сортировки суффиксов циклической строки]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Касаи | Википедия {{---}} Алгоритм Касаи]]&lt;br /&gt;
* [http://citeseer.ist.psu.edu/viewdoc/summary?doi=10.1.1.118.8221  T.Kasai, G.Lee, H.Arimura, S.Arikawa, K.Park - Linear-Time Longest-Common-Prefix Computation in Suffix Arrays and Its Application]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Суффиксный массив]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54931</id>
		<title>QpmtnCmax</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54931"/>
				<updated>2016-06-07T23:35:04Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; станков с разной скоростью выполнения работ, работающих параллельно, и &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ. Работа может быть прервана в любой момент и продолжена позже на любой машине. Необходимо минимизировать время выполнения всех работ.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм построения расписания==&lt;br /&gt;
===Описание алгоритма===&lt;br /&gt;
Перед выполнением алгоритма, упорядочим все работы по убыванию их времени выполнения:&amp;lt;tex&amp;gt; p_1 \geqslant p_2 \geqslant p_3 \ldots \geqslant p_n&amp;lt;/tex&amp;gt;, а все машины в порядке убывания скоростей: &amp;lt;tex&amp;gt; s_1 \geqslant s_2 \geqslant s_3 \ldots \geqslant s_m&amp;lt;/tex&amp;gt;. Введем следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;P_i = p_1 + \ldots + p_i&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;i = 1 \ldots n&amp;lt;/tex&amp;gt; {{---}} сумма первых &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; работ&lt;br /&gt;
*&amp;lt;tex&amp;gt;S_j = s_1 + \ldots + s_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;j = 1 \ldots m&amp;lt;/tex&amp;gt; {{---}} сумма скоростей первых &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; станков&lt;br /&gt;
&lt;br /&gt;
Необходимое условие для выполнения всех работ в интервале &amp;lt;tex&amp;gt;[0 \ldots T]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_n = p_1 + \ldots + p_n \leqslant s_1T + \ldots + s_mT = S_mT&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;\dfrac{P_n}{S_m} \leqslant T&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кроме того, должно выполняться условие &amp;lt;tex&amp;gt;\dfrac{P_j}{S_j} \leqslant T&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; j = 1 \ldots m - 1 &amp;lt;/tex&amp;gt;, так как это нижняя оценка времени выполнения работ &amp;lt;tex&amp;gt; J_1 \ldots J_j&amp;lt;/tex&amp;gt;. Исходя из этого получаем нижнюю границу &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перейдем к описанию алгоритма. Будем назвать &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-ом работы &amp;lt;tex&amp;gt; p_i(t) &amp;lt;/tex&amp;gt; невыполненную часть работы &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; t &amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Далее построим расписание, которое достигает нашей оценки &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;, с помощью &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритма.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; принимает на вход два массива — массив с объемами работ и массив скоростей обработки станков, и возвращает вектор четвёрок, где первый элемент является номером станка, второй — номером работы, а два оставшихся время начала и окончания обработки этой работы на этом станке.&lt;br /&gt;
   '''function''' level(p : '''int[n]''', s : '''int[m]''') : '''vector&amp;lt;int, int, int, int&amp;gt;'''&lt;br /&gt;
      '''vector&amp;lt;int, int, int, int&amp;gt;''' ans&lt;br /&gt;
      '''int''' t = 0&lt;br /&gt;
      '''int''' k = n  &amp;lt;font color=green&amp;gt; // количество еще не выполненных работ &amp;lt;/font&amp;gt;&lt;br /&gt;
      sort(p)  &amp;lt;font color=green&amp;gt; // сортируем время обработки работ по убыванию &amp;lt;/font&amp;gt;&lt;br /&gt;
      sort(s)  &amp;lt;font color=green&amp;gt; // сортируем станки по убыванию скоростей &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''while''' k &amp;gt; 0&lt;br /&gt;
         '''int[]''' to = assign(p, k, m)  &amp;lt;font color=green&amp;gt; // получаем распределение работ по станкам &amp;lt;/font&amp;gt;&lt;br /&gt;
         Найдем минимальное dt1 отличное от нуля такое, что (p[i] - s[to[i]] * dt1) = 0&lt;br /&gt;
         Найдем минимальное dt2 такое, что p[i] &amp;gt; p[j] и (p[i] - s[to[i]] * dt2 = p[j] - s[to[j]] * dt2)  &amp;lt;font color=green&amp;gt; // то есть такое минимальное время, через которое, &amp;lt;/font&amp;gt;&lt;br /&gt;
                                                                                                         &amp;lt;font color=green&amp;gt; // оставшийся объем каких-нибудь двух работ сравняется &amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' dt = min(dt1, dt2)&lt;br /&gt;
         '''for''' j = 0 '''to''' n - 1&lt;br /&gt;
            '''if''' p[j] &amp;gt; 0&lt;br /&gt;
               '''if''' to[j] &amp;lt;tex&amp;gt; \neq &amp;lt;/tex&amp;gt; -1  &amp;lt;font color=green&amp;gt; // рассматриваем работы которые обрабатываются в данном распределении&amp;lt;/font&amp;gt;&lt;br /&gt;
                  ans.push(to[j], j, t, t + dt)&lt;br /&gt;
                  p[j] -= s[to[i]] * dt&lt;br /&gt;
                  '''if''' p[j] == 0&lt;br /&gt;
                     k--&lt;br /&gt;
         t += dt  &amp;lt;font color=green&amp;gt; // поиск следующего момента времени, в который нужно будет перераспределить машины/работы &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' ans&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{assign}&amp;lt;/tex&amp;gt; принимает на вход массив с объемами работ и возвращает массив с распределением работ.&lt;br /&gt;
   '''function''' assign(p : '''int[n]''', k : '''int''', m : '''int''') : '''int[]'''&lt;br /&gt;
      '''int[n]''' to  &amp;lt;font color=green&amp;gt; // j работа обрабатывается на to[j] станке &amp;lt;/font&amp;gt;&lt;br /&gt;
      fill(to, -1)&lt;br /&gt;
      '''set&amp;lt;int&amp;gt;''' s  &amp;lt;font color=green&amp;gt; // множество уже распределенных работ &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''int''' i = 0&lt;br /&gt;
      '''while''' i &amp;lt; m '''and''' i &amp;lt; k&lt;br /&gt;
         Находим первый j такой что p[j] максимальный и s не содержит j&lt;br /&gt;
         s.add(j)&lt;br /&gt;
         m[j] = i++&lt;br /&gt;
      '''return''' to&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритм вызывает функцию &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; в самом худшем случае &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; раз. Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; выполняется за &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;. Итоговое время работы &amp;lt;tex&amp;gt;O(n^2m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Доказательство корректности алгоритма===&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=Расписание, построенное данным алгоритмом, является корректным и оптимальным.&lt;br /&gt;
|proof=Так как нижняя граница &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то достаточно показать, что составленное расписание достигает этой оценки.&lt;br /&gt;
&lt;br /&gt;
Будем считать, что в начале алгоритма все работы упорядочены, как было сказано ранее: &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_n(0) &amp;lt;/tex&amp;gt;. Это утверждение не меняется на протяжении всего выполнения алгоритма, для любого момента времени. Получаем: &amp;lt;tex&amp;gt; p_1(t) \geqslant p_2(t) \geqslant \ldots \geqslant p_n(t) &amp;lt;/tex&amp;gt;. Докажем что алгоритм составляет расписание в соответствии с этим свойством. Чтобы доказать этот факт, будем считать что в любой момент времени &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; нет простоев машин, когда есть хотя бы одна невыполненная работа. Получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  T(s_1 + \ldots + s_m) = p_1 + p_2 + \ldots + p_n &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; T = \dfrac{P_n}{S_m} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом необходимая оценка достигается нашим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
Допустим хотя бы одна машина простаивает, в момент когда есть невыполненные работы, получим следующее неравенство для времен окончания работ (обозначим далее как &amp;lt;tex&amp;gt; f_i &amp;lt;/tex&amp;gt;) на станках &amp;lt;tex&amp;gt;M_1 \ldots M_m&amp;lt;/tex&amp;gt;, пронумерованных по убыванию скоростей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; f_1 \geqslant f_2 \geqslant \ldots \geqslant f_m &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем написанное выше неравенство:&lt;br /&gt;
&lt;br /&gt;
Предположим, что &amp;lt;tex&amp;gt; f_i &amp;lt; f_{i+1} &amp;lt;/tex&amp;gt; для некоторого &amp;lt;tex&amp;gt; 1 \leqslant i \leqslant m-1 &amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы, выполнявшейся на станке &amp;lt;tex&amp;gt; M_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; f_i - \varepsilon &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; \varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt; достаточно мал) меньше, чем &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы на станке &amp;lt;tex&amp;gt; M_{i+1} &amp;lt;/tex&amp;gt;. Пришли к противоречию, так как при распределении, работы с наибольшим &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; выставлялись на самые быстрые станки.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; f_1 = f_2 = f_3 = \ldots = f_j &amp;gt; f_{j+1}&amp;lt;/tex&amp;gt; ,где &amp;lt;tex&amp;gt; j &amp;lt; m &amp;lt;/tex&amp;gt;. Чтобы работы завершились в момент времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;, необходимо начать их в момент времени 0, поскольку если это не выполняется, то у нас найдется работа &amp;lt;tex&amp;gt; J_i &amp;lt;/tex&amp;gt; , которая начинается позже &amp;lt;tex&amp;gt; t = 0 &amp;lt;/tex&amp;gt; и заканчивается в &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Это означает, что в момент времени &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; начинаются как минимум &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ. Пусть первые &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ стартовали вместе на всех машинах. Мы получаем &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_m(0) \geqslant p_i(0) &amp;lt;/tex&amp;gt;, из чего следует, что &amp;lt;tex&amp;gt; p_1(T - \varepsilon) \geqslant \ldots \geqslant p_m(T - \varepsilon) \geqslant p_i(T - \varepsilon) &amp;gt; 0 &amp;lt;/tex&amp;gt; для любого &amp;lt;tex&amp;gt; \varepsilon &amp;lt;/tex&amp;gt;, удовлетворяющего условию &amp;lt;tex&amp;gt; 0 \leqslant \varepsilon &amp;lt; T - t &amp;lt;/tex&amp;gt;. Таким образом, до момента времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; нет простаивающих машин. Пришли к противоречию. Получаем &amp;lt;tex&amp;gt; T = \dfrac{P_j}{S_j} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:Qpmtncmax.png|600px|thumb|right|Картинка к примеру]]&lt;br /&gt;
&lt;br /&gt;
Пусть у нас есть &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; станка. Покажем работу алгоритма для данного случая.&lt;br /&gt;
&lt;br /&gt;
В начальный момент времени начинаем обрабатывать работы с наибольшим временем выполнения &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; на станках &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt; соответственно. В момент времени &amp;lt;tex&amp;gt;T_1&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;-ой работы и &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;-ой работы совпадает. С этого момента начинаем обрабатывать работы &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; синхронно на станках: &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_2&amp;lt;/tex&amp;gt; работа &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; опускается до уровня работы &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt;.Работы &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt; выполняем одновременно на одном станке &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_3&amp;lt;/tex&amp;gt; начинаем выполнять первые четыре работы на всех станках одновременно, далее просто добавятся работы &amp;lt;tex&amp;gt;J_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_6&amp;lt;/tex&amp;gt;, и все работы закончатся одновременно.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[QpmtnSumCi|&amp;lt;tex&amp;gt;Q \mid pmtn \mid \sum C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Peter Brucker. «Scheduling Algorithms» {{---}} «Springer», 2006 г. {{---}} 124 {{---}} 129 стр. {{---}} ISBN 978-3-540-69515-8&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Теория расписаний]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54929</id>
		<title>QpmtnCmax</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54929"/>
				<updated>2016-06-07T22:39:27Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: переписан псевдокод&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; станков с разной скоростью выполнения работ, работающих параллельно, и &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ. Работа может быть прервана в любой момент и продолжена позже на любой машине. Необходимо минимизировать время выполнения всех работ.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм построения расписания==&lt;br /&gt;
===Описание алгоритма===&lt;br /&gt;
Перед выполнением алгоритма, упорядочим все работы по убыванию их времени выполнения:&amp;lt;tex&amp;gt; p_1 \geqslant p_2 \geqslant p_3 \ldots \geqslant p_n&amp;lt;/tex&amp;gt;, а все машины в порядке убывания скоростей: &amp;lt;tex&amp;gt; s_1 \geqslant s_2 \geqslant s_3 \ldots \geqslant s_m&amp;lt;/tex&amp;gt;. Введем следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
*&amp;lt;tex&amp;gt;P_i = p_1 + \ldots + p_i&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;i = 1 \ldots n&amp;lt;/tex&amp;gt; {{---}} сумма первых &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; работ&lt;br /&gt;
*&amp;lt;tex&amp;gt;S_j = s_1 + \ldots + s_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;j = 1 \ldots m&amp;lt;/tex&amp;gt; {{---}} сумма первых &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; станков&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; {{---}} время выполнения &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой работы, &amp;lt;tex&amp;gt; s_j&amp;lt;/tex&amp;gt; {{---}} скорость работы &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt;-oй машины.&lt;br /&gt;
&lt;br /&gt;
Необходимое условие для выполнения всех работ в интервале &amp;lt;tex&amp;gt;[0 \ldots T]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_n = p_1 + \ldots + p_n \leqslant s_1T + \ldots + s_mT = S_mT&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;\dfrac{P_n}{S_m} \leqslant T&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кроме того, должно выполняться условие &amp;lt;tex&amp;gt;\dfrac{P_j}{S_j} \leqslant T&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; j = 1 \ldots m - 1 &amp;lt;/tex&amp;gt;, так как это нижняя оценка времени выполнения работ &amp;lt;tex&amp;gt; J_1 \ldots J_j&amp;lt;/tex&amp;gt;. Исходя из этого получаем нижнюю границу &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перейдем к описанию алгоритма. Будем назвать &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-ом работы &amp;lt;tex&amp;gt; p_i(t) &amp;lt;/tex&amp;gt; невыполненную часть работы &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; t &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Далее построим расписание, которое достигает нашей оценки &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;, с помощью &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритма.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; принимает на вход два массива — массив с объемами работ и массив скоростей обработки станков, и возвращает вектор четвёрок, где первый элемент является номером станка, второй — номером работы, а два оставшихся время начала и окончания обработки этой работы на этом станке.&lt;br /&gt;
   '''function''' level(p : '''int[]''', s : '''int[]''', n : '''int''', m : '''int''') : '''vector&amp;lt;int, int, int, int&amp;gt;'''&lt;br /&gt;
      '''vector&amp;lt;int, int, int, int&amp;gt;''' ans&lt;br /&gt;
      '''int''' t = 0&lt;br /&gt;
      '''int''' k = n&lt;br /&gt;
      sort(p)  &amp;lt;font color=green&amp;gt; // сортируем время обработки работ по убыванию &amp;lt;/font&amp;gt;&lt;br /&gt;
      sort(s)  &amp;lt;font color=green&amp;gt; // сортируем станки по убыванию скоростей &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''while''' k &amp;gt; 0&lt;br /&gt;
         '''int[]''' to = assign(p, k, m)  &amp;lt;font color=green&amp;gt; // получаем распределение работ по станкам &amp;lt;/font&amp;gt;&lt;br /&gt;
         Найдем минимальное dt1 отличное от нуля такое, что (p[i] - s[to[i]] * dt1) = 0&lt;br /&gt;
         Найдем минимальное dt2 отличное от нуля такое, что p[i] &amp;gt; p[j] и (p[i] - s[to[i]] * dt2 = p[j] - s[to[j]] * dt2)&lt;br /&gt;
         '''int''' dt = min(dt1, dt2)&lt;br /&gt;
         '''for''' j = 0 '''to''' n - 1&lt;br /&gt;
            '''if''' p[j] &amp;gt; 0&lt;br /&gt;
               '''if''' to[j] &amp;lt;tex&amp;gt; \neq &amp;lt;/tex&amp;gt; -1  &amp;lt;font color=green&amp;gt; // рассматриваем работы которые обрабатываются в данном распределении&amp;lt;/font&amp;gt;&lt;br /&gt;
                  ans.push(to[j], j, t, t + dt)&lt;br /&gt;
                  p[j] -= s[to[i]] * dt&lt;br /&gt;
                  '''if''' p[j] == 0&lt;br /&gt;
                     k--&lt;br /&gt;
         t += dt  &amp;lt;font color=green&amp;gt; // поиск следующего момента времени, в который нужно будет перераспределить машины/работы &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''return''' ans&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{assign}&amp;lt;/tex&amp;gt; принимает на вход массив с объемами работ и возвращает массив с распределением работ.&lt;br /&gt;
   '''function''' assign (p : '''int[]''', n : '''int''', m : '''int''') : '''int[]'''&lt;br /&gt;
      '''int[]''' to  &amp;lt;font color=green&amp;gt; // j работа обрабатывается на to[j] станке &amp;lt;/font&amp;gt;&lt;br /&gt;
      fill(to, -1)&lt;br /&gt;
      '''int''' i = 0&lt;br /&gt;
      '''while''' i &amp;lt; m '''and''' i &amp;lt; n&lt;br /&gt;
         Находим первый j такой что p[j] максимальный&lt;br /&gt;
         m[j] = i++&lt;br /&gt;
      '''return''' to&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритм вызывает функцию &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; в самом худшем случае &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; раз. Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; выполняется за &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;. Итоговое время работы &amp;lt;tex&amp;gt;O(n^2m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Доказательство корректности алгоритма===&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=Расписание, построенное данным алгоритмом, является корректным и оптимальным.&lt;br /&gt;
|proof=Так как нижняя граница &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то достаточно показать, что составленное расписание достигает этой оценки.&lt;br /&gt;
&lt;br /&gt;
Будем считать, что в начале алгоритма все работы упорядочены, как было сказано ранее: &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_n(0) &amp;lt;/tex&amp;gt;. Это утверждение не меняется на протяжении всего выполнения алгоритма, для любого момента времени. Получаем: &amp;lt;tex&amp;gt; p_1(t) \geqslant p_2(t) \geqslant \ldots \geqslant p_n(t) &amp;lt;/tex&amp;gt;. Докажем что алгоритм составляет расписание в соответствии с этим свойством. Чтобы доказать этот факт, будем считать что в любой момент времени &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; нет простоев машин, когда есть хотя бы одна невыполненная работа. Получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  T(s_1 + \ldots + s_m) = p_1 + p_2 + \ldots + p_n &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; T = \dfrac{P_n}{S_m} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом необходимая оценка достигается нашим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
Допустим хотя бы одна машина простаивает, в момент когда есть невыполненные работы, получим следующее неравенство для времен окончания работ (обозначим далее как &amp;lt;tex&amp;gt; f_i &amp;lt;/tex&amp;gt;) на станках &amp;lt;tex&amp;gt;M_1 \ldots M_m&amp;lt;/tex&amp;gt;, пронумерованных по убыванию скоростей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; f_1 \geqslant f_2 \geqslant \ldots \geqslant f_m &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем написанное выше неравенство:&lt;br /&gt;
&lt;br /&gt;
Предположим, что &amp;lt;tex&amp;gt; f_i &amp;lt; f_{i+1} &amp;lt;/tex&amp;gt; для некоторого &amp;lt;tex&amp;gt; 1 \leqslant i \leqslant m-1 &amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы, выполнявшейся на станке &amp;lt;tex&amp;gt; M_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; f_i - \varepsilon &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; \varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt; достаточно мал) меньше, чем &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы на станке &amp;lt;tex&amp;gt; M_{i+1} &amp;lt;/tex&amp;gt;. Пришли к противоречию, так как при распределении, работы с наибольшим &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; выставлялись на самые быстрые станки.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; f_1 = f_2 = f_3 = \ldots = f_j &amp;gt; f_{j+1}&amp;lt;/tex&amp;gt; ,где &amp;lt;tex&amp;gt; j &amp;lt; m &amp;lt;/tex&amp;gt;. Чтобы работы завершились в момент времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;, необходимо начать их в момент времени 0, поскольку если это не выполняется, то у нас найдется работа &amp;lt;tex&amp;gt; J_i &amp;lt;/tex&amp;gt; , которая начинается позже &amp;lt;tex&amp;gt; t = 0 &amp;lt;/tex&amp;gt; и заканчивается в &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Это означает, что в момент времени &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; начинаются как минимум &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ. Пусть первые &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ стартовали вместе на всех машинах. Мы получаем &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_m(0) \geqslant p_i(0) &amp;lt;/tex&amp;gt;, из чего следует, что &amp;lt;tex&amp;gt; p_1(T - \varepsilon) \geqslant \ldots \geqslant p_m(T - \varepsilon) \geqslant p_i(T - \varepsilon) &amp;gt; 0 &amp;lt;/tex&amp;gt; для любого &amp;lt;tex&amp;gt; \varepsilon &amp;lt;/tex&amp;gt;, удовлетворяющего условию &amp;lt;tex&amp;gt; 0 \leqslant \varepsilon &amp;lt; T - t &amp;lt;/tex&amp;gt;. Таким образом, до момента времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; нет простаивающих машин. Пришли к противоречию. Получаем &amp;lt;tex&amp;gt; T = {P_j \over S_j} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:Qpmtncmax.png|600px|thumb|right|Картинка к примеру]]&lt;br /&gt;
&lt;br /&gt;
Пусть у нас есть &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; станка. Покажем работу алгоритма для данного случая.&lt;br /&gt;
&lt;br /&gt;
В начальный момент времени начинаем обрабатывать работы с наибольшим временем выполнения &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; на станках &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt; соответственно. В момент времени &amp;lt;tex&amp;gt;T_1&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;-ой работы и &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;-ой работы совпадает. С этого момента начинаем обрабатывать работы &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; синхронно на станках: &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_2&amp;lt;/tex&amp;gt; работа &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; опускается до уровня работы &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt;.Работы &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt; выполняем одновременно на одном станке &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_3&amp;lt;/tex&amp;gt; начинаем выполнять первые четыре работы на всех станках одновременно, далее просто добавятся работы &amp;lt;tex&amp;gt;J_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_6&amp;lt;/tex&amp;gt;, и все работы закончатся одновременно.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[QpmtnSumCi|&amp;lt;tex&amp;gt;Q \mid pmtn \mid \sum C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Peter Brucker. «Scheduling Algorithms» {{---}} «Springer», 2006 г. {{---}} 124 {{---}} 129 стр. {{---}} ISBN 978-3-540-69515-8&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Теория расписаний]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54867</id>
		<title>QpmtnCmax</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54867"/>
				<updated>2016-06-07T19:16:26Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: /* Описание алгоритма */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано несколько станков с разной скоростью выполнения работ, работающих параллельно. Работа может быть прервана в любой момент и продолжена позже на любой машине. Необходимо минимизировать время выполнения всех работ.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм построения расписания==&lt;br /&gt;
===Описание алгоритма===&lt;br /&gt;
Пусть нам даны &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; станков. Перед выполнением алгоритма, упорядочим все работы по убыванию их времени выполнения:&amp;lt;tex&amp;gt; p_1 \geqslant p_2 \geqslant p_3 \ldots \geqslant p_n&amp;lt;/tex&amp;gt;, а все машины в порядке убывания скоростей: &amp;lt;tex&amp;gt; s_1 \geqslant s_2 \geqslant s_3 \ldots \geqslant s_m&amp;lt;/tex&amp;gt;. Введем следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_i = p_1 + \ldots + p_i&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; S_j = s_1 + \ldots + s_j&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 1 \ldots n&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;j = 1 \ldots m&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; {{---}} время выполнения &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой работы, &amp;lt;tex&amp;gt; s_j&amp;lt;/tex&amp;gt; {{---}} скорость работы &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt;-oй машины.&lt;br /&gt;
&lt;br /&gt;
Необходимое условие для выполнения всех работ в интервале &amp;lt;tex&amp;gt;[0 \ldots T]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_n = p_1 + \ldots + p_n \leqslant s_1T + \ldots + s_mT = S_mT&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;P_n/S_m \leqslant T&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кроме того, должно выполняться условие &amp;lt;tex&amp;gt;P_j/S_j \leqslant T&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; j = 1 \ldots m - 1 &amp;lt;/tex&amp;gt;, так как это нижняя оценка времени выполнения работ &amp;lt;tex&amp;gt; J_1 \ldots J_j&amp;lt;/tex&amp;gt;. Исходя из этого получаем нижнюю границу &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перейдем к описанию алгоритма. Будем назвать &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-ом работы &amp;lt;tex&amp;gt; p_i(t) &amp;lt;/tex&amp;gt; невыполненную часть работы &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; t &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Далее построим расписание, которое достигает нашей оценки &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;, с помощью &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритма.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
   '''function''' level():&lt;br /&gt;
       '''int''' &amp;lt;tex&amp;gt;t = 0 &amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''while''' &amp;lt;tex&amp;gt;\exists p(t) &amp;gt; 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
          assign(t)&lt;br /&gt;
          '''int''' &amp;lt;tex&amp;gt;t_1 = \min (s \mid s &amp;gt; t &amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;p(s) = 0)&amp;lt;/tex&amp;gt;&lt;br /&gt;
          '''int''' &amp;lt;tex&amp;gt;t_2 = \min (s \mid s &amp;gt; t&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;\exists i&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;j : p_i(t) &amp;gt; p_j(t)&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;p_i(s) = p_j(s))&amp;lt;/tex&amp;gt;&lt;br /&gt;
          &amp;lt;tex&amp;gt;t = \min(t_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;t_2)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // поиск следующего момента времени, в который нужно будет перераспределить машины/работы &amp;lt;/font&amp;gt;&lt;br /&gt;
       Построение расписания&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t)&amp;lt;/tex&amp;gt;:&lt;br /&gt;
   '''function''' assign (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; : '''int'''):&lt;br /&gt;
      &amp;lt;tex&amp;gt;J = \{i \mid p_i(t) &amp;gt; 0\}&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // множество работ с положительным level &amp;lt;/font&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;M = \{M_1 \ldots M_m\}&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // множество всех станков &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''while''' &amp;lt;tex&amp;gt;J \ne \varnothing&amp;lt;/tex&amp;gt; '''or''' &amp;lt;tex&amp;gt;M \ne \varnothing&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;maxLevel = \max(p_i(t) \mid i \in J)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // максимальное значение level из J &amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;count = J.getCount(maxLevel)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // количество работ с level = maxLevel &amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;r = \min(|M|&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;count)&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;I \leftarrow \{r&amp;lt;/tex&amp;gt; работ из &amp;lt;tex&amp;gt;J \mid p(t) = maxLevel\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;M' \leftarrow \{r&amp;lt;/tex&amp;gt; самых быстрых машин из &amp;lt;tex&amp;gt;M\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         Распределяем работы&lt;br /&gt;
         &amp;lt;tex&amp;gt;J \leftarrow J \setminus I&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;M \leftarrow M \setminus M'&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритм вызывает функцию &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; в самом худшем случае &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; раз. Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; выполняется за &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;. Итоговое время работы &amp;lt;tex&amp;gt;O(n^2m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Доказательство корректности алгоритма===&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=Расписание, построенное данным алгоритмом, является корректным и оптимальным.&lt;br /&gt;
|proof=Так как нижняя граница &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то достаточно показать, что составленное расписание достигает этой оценки.&lt;br /&gt;
&lt;br /&gt;
Будем считать, что в начале алгоритма все работы упорядочены, как было сказано ранее: &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_n(0) &amp;lt;/tex&amp;gt;. Это утверждение не меняется на протяжении всего выполнения алгоритма, для любого момента времени. Получаем: &amp;lt;tex&amp;gt; p_1(t) \geqslant p_2(t) \geqslant \ldots \geqslant p_n(t) &amp;lt;/tex&amp;gt;. Докажем что алгоритм составляет расписание в соответствии с этим свойством. Чтобы доказать этот факт, будем считать что в любой момент времени &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; нет простоев машин, когда есть хотя бы одна невыполненная работа. Получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  T(s_1 + \ldots + s_m) = p_1 + p_2 + \ldots + p_n &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; T = {P_n \over S_m} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом необходимая оценка достигается нашим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
Допустим хотя бы одна машина простаивает, в момент когда есть невыполненные работы, получим следующее неравенство для времен окончания работ (обозначим далее как &amp;lt;tex&amp;gt; f_i &amp;lt;/tex&amp;gt;) на станках &amp;lt;tex&amp;gt;M_1 \ldots M_m&amp;lt;/tex&amp;gt;, пронумерованных по убыванию скоростей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; f_1 \geqslant f_2 \geqslant \ldots \geqslant f_m &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем написанное выше неравенство:&lt;br /&gt;
&lt;br /&gt;
Предположим, что &amp;lt;tex&amp;gt; f_i &amp;lt; f_{i+1} &amp;lt;/tex&amp;gt; для некоторого &amp;lt;tex&amp;gt; 1 \leqslant i \leqslant m-1 &amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы, выполнявшейся на станке &amp;lt;tex&amp;gt; M_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; f_i - \varepsilon &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; \varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt; достаточно мал) меньше, чем &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы на станке &amp;lt;tex&amp;gt; M_{i+1} &amp;lt;/tex&amp;gt;. Пришли к противоречию, так как при распределении, работы с наибольшим &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; выставлялись на самые быстрые станки.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; f_1 = f_2 = f_3 = \ldots = f_j &amp;gt; f_{j+1}&amp;lt;/tex&amp;gt; ,где &amp;lt;tex&amp;gt; j &amp;lt; m &amp;lt;/tex&amp;gt;. Чтобы работы завершились в момент времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;, необходимо начать их в момент времени 0, поскольку если это не выполняется, то у нас найдется работа &amp;lt;tex&amp;gt; J_i &amp;lt;/tex&amp;gt; , которая начинается позже &amp;lt;tex&amp;gt; t = 0 &amp;lt;/tex&amp;gt; и заканчивается в &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Это означает, что в момент времени &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; начинаются как минимум &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ. Пусть первые &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ стартовали вместе на всех машинах. Мы получаем &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_m(0) \geqslant p_i(0) &amp;lt;/tex&amp;gt;, из чего следует, что &amp;lt;tex&amp;gt; p_1(T - \varepsilon) \geqslant \ldots \geqslant p_m(T - \varepsilon) \geqslant p_i(T - \varepsilon) &amp;gt; 0 &amp;lt;/tex&amp;gt; для любого &amp;lt;tex&amp;gt; \varepsilon &amp;lt;/tex&amp;gt;, удовлетворяющего условию &amp;lt;tex&amp;gt; 0 \leqslant \varepsilon &amp;lt; T - t &amp;lt;/tex&amp;gt;. Таким образом, до момента времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; нет простаивающих машин. Пришли к противоречию. Получаем &amp;lt;tex&amp;gt; T = {P_j \over S_j} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:Qpmtncmax.png|600px|thumb|right|Картинка к примеру]]&lt;br /&gt;
&lt;br /&gt;
Пусть у нас есть &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; станка. Покажем работу алгоритма для данного случая.&lt;br /&gt;
&lt;br /&gt;
В начальный момент времени начинаем обрабатывать работы с наибольшим временем выполнения &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; на станках &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt; соответственно. В момент времени &amp;lt;tex&amp;gt;T_1&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;-ой работы и &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;-ой работы совпадает. С этого момента начинаем обрабатывать работы &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; синхронно на станках: &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_2&amp;lt;/tex&amp;gt; работа &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; опускается до уровня работы &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt;.Работы &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt; выполняем одновременно на одном станке &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_3&amp;lt;/tex&amp;gt; начинаем выполнять первые четыре работы на всех станках одновременно, далее просто добавятся работы &amp;lt;tex&amp;gt;J_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_6&amp;lt;/tex&amp;gt;, и все работы закончатся одновременно.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[QpmtnSumCi|&amp;lt;tex&amp;gt;Q \mid pmtn \mid \sum C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Peter Brucker. «Scheduling Algorithms» {{---}} «Springer», 2006 г. {{---}} 124 {{---}} 129 стр. {{---}} ISBN 978-3-540-69515-8&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Теория расписаний]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54865</id>
		<title>QpmtnCmax</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=QpmtnCmax&amp;diff=54865"/>
				<updated>2016-06-07T19:14:27Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt;Q \mid pmtn \mid C_{max}&amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано несколько станков с разной скоростью выполнения работ, работающих параллельно. Работа может быть прервана в любой момент и продолжена позже на любой машине. Необходимо минимизировать время выполнения всех работ.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Алгоритм построения расписания==&lt;br /&gt;
===Описание алгоритма===&lt;br /&gt;
Пусть нам даны &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; станков. Перед выполнением алгоритма, упорядочим все работы по убыванию их времени выполнения:&amp;lt;tex&amp;gt; p_1 \geqslant p_2 \geqslant p_3 \ldots \geqslant p_n&amp;lt;/tex&amp;gt;, а все машины в порядке убывания скоростей: &amp;lt;tex&amp;gt; s_1 \geqslant s_2 \geqslant s_3 \ldots \geqslant s_m&amp;lt;/tex&amp;gt;. Введем следующие обозначения:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_i = p_1 + \ldots + p_i&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; S_j = s_1 + \ldots + s_j&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;i = 1 \ldots n&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;j = 1 \ldots m&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; {{---}} время выполнения &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;-ой работы, &amp;lt;tex&amp;gt; s_j&amp;lt;/tex&amp;gt; {{---}} скорость работы &amp;lt;tex&amp;gt; j &amp;lt;/tex&amp;gt;-oй машины.&lt;br /&gt;
&lt;br /&gt;
Необходимое условие для выполнения всех работ в интервале &amp;lt;tex&amp;gt;[0..T]&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; P_n = p_1 + \ldots + p_n \leqslant s_1T + \ldots + s_mT = S_mT&amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt;P_n/S_m \leqslant T&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Кроме того, должно выполняться условие &amp;lt;tex&amp;gt;P_j/S_j \leqslant T&amp;lt;/tex&amp;gt; для всех &amp;lt;tex&amp;gt; j = 1 \ldots m - 1 &amp;lt;/tex&amp;gt;, так как это нижняя оценка времени выполнения работ &amp;lt;tex&amp;gt; J_1 \ldots J_j&amp;lt;/tex&amp;gt;. Исходя из этого получаем нижнюю границу &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt; :&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Перейдем к описанию алгоритма. Будем назвать &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-ом работы &amp;lt;tex&amp;gt; p_i(t) &amp;lt;/tex&amp;gt; - невыполненную часть работы &amp;lt;tex&amp;gt; p_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; t &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Далее построим расписание, которое достигает нашей оценки &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;, с помощью &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритма.&lt;br /&gt;
&lt;br /&gt;
===Псевдокод===&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
   '''function''' level():&lt;br /&gt;
       '''int''' &amp;lt;tex&amp;gt;t = 0 &amp;lt;/tex&amp;gt;&lt;br /&gt;
       '''while''' &amp;lt;tex&amp;gt;\exists p(t) &amp;gt; 0&amp;lt;/tex&amp;gt;&lt;br /&gt;
          assign(t)&lt;br /&gt;
          '''int''' &amp;lt;tex&amp;gt;t_1 = \min (s \mid s &amp;gt; t &amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;p(s) = 0)&amp;lt;/tex&amp;gt;&lt;br /&gt;
          '''int''' &amp;lt;tex&amp;gt;t_2 = \min (s \mid s &amp;gt; t&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;\exists i&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;j : p_i(t) &amp;gt; p_j(t)&amp;lt;/tex&amp;gt; '''and''' &amp;lt;tex&amp;gt;p_i(s) = p_j(s))&amp;lt;/tex&amp;gt;&lt;br /&gt;
          &amp;lt;tex&amp;gt;t = \min(t_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;t_2)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // поиск следующего момента времени, в который нужно будет перераспределить машины/работы &amp;lt;/font&amp;gt;&lt;br /&gt;
       Построение расписания&lt;br /&gt;
&lt;br /&gt;
Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t)&amp;lt;/tex&amp;gt;:&lt;br /&gt;
   '''function''' assign (&amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; : '''int'''):&lt;br /&gt;
      &amp;lt;tex&amp;gt;J = \{i \mid p_i(t) &amp;gt; 0\}&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // множество работ с положительным level &amp;lt;/font&amp;gt;&lt;br /&gt;
      &amp;lt;tex&amp;gt;M = \{M_1 \ldots M_m\}&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // множество всех станков &amp;lt;/font&amp;gt;&lt;br /&gt;
      '''while''' &amp;lt;tex&amp;gt;J \ne \varnothing&amp;lt;/tex&amp;gt; '''or''' &amp;lt;tex&amp;gt;M \ne \varnothing&amp;lt;/tex&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;maxLevel = \max(p_i(t) \mid i \in J)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // максимальное значение level из J &amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;count = J.getCount(maxLevel)&amp;lt;/tex&amp;gt;  &amp;lt;font color=green&amp;gt; // количество работ с level = maxLevel &amp;lt;/font&amp;gt;&lt;br /&gt;
         '''int''' &amp;lt;tex&amp;gt;r = \min(|M|&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;count)&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;I \leftarrow \{r&amp;lt;/tex&amp;gt; работ из &amp;lt;tex&amp;gt;J \mid p(t) = maxLevel\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;M' \leftarrow \{r&amp;lt;/tex&amp;gt; самых быстрых машин из &amp;lt;tex&amp;gt;M\}&amp;lt;/tex&amp;gt;&lt;br /&gt;
         Распределяем работы&lt;br /&gt;
         &amp;lt;tex&amp;gt;J \leftarrow J \setminus I&amp;lt;/tex&amp;gt;&lt;br /&gt;
         &amp;lt;tex&amp;gt;M \leftarrow M \setminus M'&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Асимптотика===&lt;br /&gt;
&amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt;-алгоритм вызывает функцию &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; в самом худшем случае &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; раз. Функция &amp;lt;tex&amp;gt;\mathrm{assign}(t) &amp;lt;/tex&amp;gt; выполняется за &amp;lt;tex&amp;gt;O(nm)&amp;lt;/tex&amp;gt;. Итоговое время работы &amp;lt;tex&amp;gt;O(n^2m)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
===Доказательство корректности алгоритма===&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=Расписание, построенное данным алгоритмом, является корректным и оптимальным.&lt;br /&gt;
|proof=Так как нижняя граница &amp;lt;tex&amp;gt;C_{max}&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;C_{max} = \max&lt;br /&gt;
\left \{\begin{array}{ll} \dfrac{P_n}{S_m}  \\&lt;br /&gt;
\max\limits_{j=1 \ldots m-1} \dfrac{P_j}{S_j} \end{array} \right. &lt;br /&gt;
&amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
то достаточно показать, что составленное расписание достигает этой оценки.&lt;br /&gt;
&lt;br /&gt;
Будем считать, что в начале алгоритма все работы упорядочены, как было сказано ранее: &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_n(0) &amp;lt;/tex&amp;gt;. Это утверждение не меняется на протяжении всего выполнения алгоритма, для любого момента времени. Получаем: &amp;lt;tex&amp;gt; p_1(t) \geqslant p_2(t) \geqslant \ldots \geqslant p_n(t) &amp;lt;/tex&amp;gt;. Докажем что алгоритм составляет расписание в соответствии с этим свойством. Чтобы доказать этот факт, будем считать что в любой момент времени &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; нет простоев машин, когда есть хотя бы одна невыполненная работа. Получаем:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt;  T(s_1 + \ldots + s_m) = p_1 + p_2 + \ldots + p_n &amp;lt;/tex&amp;gt; или &amp;lt;tex&amp;gt; T = {P_n \over S_m} &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Таким образом необходимая оценка достигается нашим алгоритмом.&lt;br /&gt;
&lt;br /&gt;
Допустим хотя бы одна машина простаивает, в момент когда есть невыполненные работы, получим следующее неравенство для времен окончания работ (обозначим далее как &amp;lt;tex&amp;gt; f_i &amp;lt;/tex&amp;gt;) на станках &amp;lt;tex&amp;gt;M_1 \ldots M_m&amp;lt;/tex&amp;gt;, пронумерованных по убыванию скоростей:&lt;br /&gt;
&lt;br /&gt;
&amp;lt;tex&amp;gt; f_1 \geqslant f_2 \geqslant \ldots \geqslant f_m &amp;lt;/tex&amp;gt;&lt;br /&gt;
&lt;br /&gt;
Докажем написанное выше неравенство:&lt;br /&gt;
&lt;br /&gt;
Предположим, что &amp;lt;tex&amp;gt; f_i &amp;lt; f_{i+1} &amp;lt;/tex&amp;gt; для некоторого &amp;lt;tex&amp;gt; 1 \leqslant i \leqslant m-1 &amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы, выполнявшейся на станке &amp;lt;tex&amp;gt; M_i &amp;lt;/tex&amp;gt; в момент времени &amp;lt;tex&amp;gt; f_i - \varepsilon &amp;lt;/tex&amp;gt; (где &amp;lt;tex&amp;gt; \varepsilon &amp;gt; 0&amp;lt;/tex&amp;gt; достаточно мал) меньше, чем &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; последней работы на станке &amp;lt;tex&amp;gt; M_{i+1} &amp;lt;/tex&amp;gt;. Пришли к противоречию, так как при распределении, работы с наибольшим &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; выставлялись на самые быстрые станки.&lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; = &amp;lt;tex&amp;gt; f_1 = f_2 = f_3 = \ldots = f_j &amp;gt; f_{j+1}&amp;lt;/tex&amp;gt; ,где &amp;lt;tex&amp;gt; j &amp;lt; m &amp;lt;/tex&amp;gt;. Чтобы работы завершились в момент времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;, необходимо начать их в момент времени 0, поскольку если это не выполняется, то у нас найдется работа &amp;lt;tex&amp;gt; J_i &amp;lt;/tex&amp;gt; , которая начинается позже &amp;lt;tex&amp;gt; t = 0 &amp;lt;/tex&amp;gt; и заканчивается в &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt;. Это означает, что в момент времени &amp;lt;tex&amp;gt; 0 &amp;lt;/tex&amp;gt; начинаются как минимум &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ. Пусть первые &amp;lt;tex&amp;gt; m &amp;lt;/tex&amp;gt; работ стартовали вместе на всех машинах. Мы получаем &amp;lt;tex&amp;gt; p_1(0) \geqslant p_2(0) \geqslant \ldots \geqslant p_m(0) \geqslant p_i(0) &amp;lt;/tex&amp;gt;, из чего следует, что &amp;lt;tex&amp;gt; p_1(T - \varepsilon) \geqslant \ldots \geqslant p_m(T - \varepsilon) \geqslant p_i(T - \varepsilon) &amp;gt; 0 &amp;lt;/tex&amp;gt; для любого &amp;lt;tex&amp;gt; \varepsilon &amp;lt;/tex&amp;gt;, удовлетворяющего условию &amp;lt;tex&amp;gt; 0 \leqslant \varepsilon &amp;lt; T - t &amp;lt;/tex&amp;gt;. Таким образом, до момента времени &amp;lt;tex&amp;gt; T &amp;lt;/tex&amp;gt; нет простаивающих машин. Пришли к противоречию. Получаем &amp;lt;tex&amp;gt; T = {P_j \over S_j} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Пример===&lt;br /&gt;
[[Файл:Qpmtncmax.png|600px|thumb|right|Картинка к примеру]]&lt;br /&gt;
&lt;br /&gt;
Пусть у нас есть &amp;lt;tex&amp;gt;6&amp;lt;/tex&amp;gt; работ и &amp;lt;tex&amp;gt;3&amp;lt;/tex&amp;gt; станка. Покажем работу алгоритма для данного случая.&lt;br /&gt;
&lt;br /&gt;
В начальный момент времени начинаем обрабатывать работы с наибольшим временем выполнения &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; на станках &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt; соответственно. В момент времени &amp;lt;tex&amp;gt;T_1&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;\mathrm{level}&amp;lt;/tex&amp;gt; &amp;lt;tex&amp;gt;1&amp;lt;/tex&amp;gt;-ой работы и &amp;lt;tex&amp;gt;2&amp;lt;/tex&amp;gt;-ой работы совпадает. С этого момента начинаем обрабатывать работы &amp;lt;tex&amp;gt;J_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_2&amp;lt;/tex&amp;gt; синхронно на станках: &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_2&amp;lt;/tex&amp;gt; работа &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; опускается до уровня работы &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt;.Работы &amp;lt;tex&amp;gt;J_3&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_4&amp;lt;/tex&amp;gt; выполняем одновременно на одном станке &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt;. В момент времени &amp;lt;tex&amp;gt;T_3&amp;lt;/tex&amp;gt; начинаем выполнять первые четыре работы на всех станках одновременно, далее просто добавятся работы &amp;lt;tex&amp;gt;J_5&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_6&amp;lt;/tex&amp;gt;, и все работы закончатся одновременно.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[QpmtnSumCi|&amp;lt;tex&amp;gt;Q \mid pmtn \mid \sum C_i&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* Peter Brucker. «Scheduling Algorithms» {{---}} «Springer», 2006 г. {{---}} 124 {{---}} 129 стр. {{---}} ISBN 978-3-540-69515-8&lt;br /&gt;
&lt;br /&gt;
[[Категория: Дискретная математика и алгоритмы]]&lt;br /&gt;
[[Категория: Теория расписаний]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=Ppi1riintegerLmax&amp;diff=54414</id>
		<title>Ppi1riintegerLmax</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=Ppi1riintegerLmax&amp;diff=54414"/>
				<updated>2016-06-04T10:51:30Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: корректность&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt; P \mid p_i=1; r_i - integer \mid L_{max} &amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; однородных станков, работающих параллельно, и &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ с временем выполнения &amp;lt;tex&amp;gt;p_i = 1&amp;lt;/tex&amp;gt;, временем появления &amp;lt;tex&amp;gt;r_i&amp;lt;/tex&amp;gt;, заданным целым числом, и момент времени &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;, к которому нужно выполнить работу. Необходимо построить такое расписание, чтобы значение максимального опоздания &amp;lt;tex&amp;gt;L_{max} = \max\limits_{i=1\ldots n} (C_i - d_i)&amp;lt;/tex&amp;gt; было минимальным.&lt;br /&gt;
}}&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
=== Идея ===&lt;br /&gt;
Отсортируем все работы по времени появления в неубывающем порядке так, что &amp;lt;tex&amp;gt;r_1 \leqslant r_2 \leqslant  \ldots  \leqslant r_n&amp;lt;/tex&amp;gt;. Теперь будем выполнять доступные на данный момент работы в порядке неубывания дедлайнов &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;. То есть, если в момент времени &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; есть свободные станки и есть невыполненные работы такие, что &amp;lt;tex&amp;gt;r_i \leqslant t&amp;lt;/tex&amp;gt;, то назначаем работу с наименьшим дедлайном &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt; на свободный станок.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
Алгоритм принимает на вход массив пар, где первый элемент является временем появления &amp;lt;tex&amp;gt;r_i&amp;lt;/tex&amp;gt; работы, а второй её дедлайном &amp;lt;tex&amp;gt;d_i&amp;lt;/tex&amp;gt;, и возвращает расписание, представленное массивом, где на позиции &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; стоит момент обработки работы &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
 '''function''' scheduling(jobs: '''&amp;lt;int, int&amp;gt;'''[n]) -&amp;gt; '''int[n]'''&lt;br /&gt;
     sort(jobs) &amp;lt;font color=green&amp;gt;// сортируем работы в порядке неубывания времени появления&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''int''' j = 1 &amp;lt;font color=green&amp;gt;// последняя невыполненная работа&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''int[n]''' ans &amp;lt;font color=green&amp;gt;// массив, куда будет записано расписание&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''heap''' M &amp;lt;font color=green&amp;gt;// куча, в которой будем хранить доступные на данный момент работы в порядке неубывания дедлайнов&amp;lt;/font&amp;gt;&lt;br /&gt;
     '''while''' j &amp;lt;= n&lt;br /&gt;
         '''int''' time = jobs[j].first &amp;lt;font color=green&amp;gt;// время начала выполнения текущего блока работ&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''while''' jobs[j].first &amp;lt;= time &amp;lt;font color=green&amp;gt;// добавляем в кучу все невыполненные работы, доступные на данный момент&amp;lt;/font&amp;gt;&lt;br /&gt;
            M.push(j)&lt;br /&gt;
            j++&lt;br /&gt;
         &lt;br /&gt;
         '''int''' k = 0 &amp;lt;font color=green&amp;gt;// количество занятых станков в данный момент времени&amp;lt;/font&amp;gt;&lt;br /&gt;
         '''while''' M.notEmpty()&lt;br /&gt;
            i = M.pop() &amp;lt;font color=green&amp;gt;// получаем доступную работу с наименьшим дедлайном &amp;lt;/font&amp;gt;&lt;br /&gt;
            ans[i] = t &amp;lt;font color=green&amp;gt;// назначаем работу i на время t&amp;lt;/font&amp;gt;&lt;br /&gt;
            '''if''' k + 1 &amp;lt; m &amp;lt;font color=green&amp;gt;// если в момент t есть свободный станок, то назначаем работу i на него&amp;lt;/font&amp;gt;&lt;br /&gt;
                k++&lt;br /&gt;
            '''else''' &amp;lt;font color=green&amp;gt;// иначе увеличиваем время и обновляем список доступных работ&amp;lt;/font&amp;gt;&lt;br /&gt;
                t++&lt;br /&gt;
                k = 0&lt;br /&gt;
                '''while''' jobs[j].first &amp;lt;= time&lt;br /&gt;
                    M.push(j)&lt;br /&gt;
                    j++&lt;br /&gt;
&lt;br /&gt;
Внутренний цикл '''while''' распределяет работы блоками, в которых они выполняются без простоя станков. После окончания такого блока, время начала выполнения следующего будет равно текущему значению &amp;lt;tex&amp;gt;r_j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
=== Асимптотика ===&lt;br /&gt;
Сначала мы сортируем работы, что занимает &amp;lt;tex&amp;gt; \mathcal{O}(n\log{n})&amp;lt;/tex&amp;gt;. Далее идёт цикл, в котором мы &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз кладём элемент в кучу и &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; раз извлекаем, что также занимает &amp;lt;tex&amp;gt; \mathcal{O}(n\log{n})&amp;lt;/tex&amp;gt; времени. В итоге всё вместе составляет асимптотику алгоритма &amp;lt;tex&amp;gt; \mathcal{O}(n\log{n})&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности алгоритма ==&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Приведенный алгоритм строит оптимальное расписание для задачи &amp;lt;tex&amp;gt; P \mid p_i=1; r_i - integer \mid L_{max} &amp;lt;/tex&amp;gt;.&lt;br /&gt;
|proof=&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; {{---}} расписание построенное предложенным алгоритмом, а &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt; оптимальное расписание со следующими свойствами:&lt;br /&gt;
* первые &amp;lt;tex&amp;gt;r-1&amp;lt;/tex&amp;gt; работ из &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; в обоих расписаниях назначены на одно и тоже время и&lt;br /&gt;
* значение &amp;lt;tex&amp;gt;r-1&amp;lt;/tex&amp;gt; {{---}} наибольшее.&lt;br /&gt;
Таким образом работа &amp;lt;tex&amp;gt;J_r&amp;lt;/tex&amp;gt; в расписании &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; назначена на время &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а в расписании &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt; на другой более поздний момент времени. Если в момент времени &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt; в расписании &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt; есть свободный станок, то работа &amp;lt;tex&amp;gt;J_r&amp;lt;/tex&amp;gt; может быть назначена на этот станок и выполнена в момент &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;. Иначе существует работа &amp;lt;tex&amp;gt;J_k&amp;lt;/tex&amp;gt; такая, что &amp;lt;tex&amp;gt;d_r \leqslant d_k&amp;lt;/tex&amp;gt;, которая выполнится в расписании &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt; в момент &amp;lt;tex&amp;gt;t&amp;lt;/tex&amp;gt;, а в &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; в другое время. Тогда мы меняем местами работы &amp;lt;tex&amp;gt;J_k&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;J_r&amp;lt;/tex&amp;gt; в расписании &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt;, что не нарушает оптимальность &amp;lt;tex&amp;gt;S^*&amp;lt;/tex&amp;gt;, но является противоречием максимальности значения &amp;lt;tex&amp;gt;r-1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== См. также ==&lt;br /&gt;
* [[Pintreepi1Lmax|&amp;lt;tex&amp;gt;P \mid intree, p_{i} = 1 \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
* [[PpmtnriLmax|&amp;lt;tex&amp;gt;P \mid pmtn, r_i \mid L_{max}&amp;lt;/tex&amp;gt;]]&lt;br /&gt;
&lt;br /&gt;
== Источники информации ==&lt;br /&gt;
* Peter Brucker «Scheduling Algorithms», fifth edition, Springer {{---}} с. 111-112 ISBN 978-3-540-69515-8&lt;br /&gt;
&lt;br /&gt;
[[Категория: Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория: Теория расписаний]]&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=QpmtnSumCi&amp;diff=54311</id>
		<title>QpmtnSumCi</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=QpmtnSumCi&amp;diff=54311"/>
				<updated>2016-05-29T22:07:11Z</updated>
		
		<summary type="html">&lt;p&gt;46.183.217.186: лемма&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;&amp;lt;tex dpi = &amp;quot;200&amp;quot;&amp;gt; Q \mid pmtn \mid \sum C_i &amp;lt;/tex&amp;gt;&lt;br /&gt;
{{Задача&lt;br /&gt;
|definition=&lt;br /&gt;
Дано &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt; станков с разной скоростью выполнения работ &amp;lt;tex&amp;gt;v_j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; работ с заданным временем выполнения &amp;lt;tex&amp;gt;p_i&amp;lt;/tex&amp;gt;. Работы можно прерывать и продолжать их выполнение на другом станке. Необходимо построить такое расписание, чтобы суммарное время окончания всех работ было минимальным.&lt;br /&gt;
}}&lt;br /&gt;
== Описание алгоритма ==&lt;br /&gt;
[[Файл:QpmtnSumCi example.png|320px|thumb|right|Пример работы алгоритма]]&lt;br /&gt;
=== Идея ===&lt;br /&gt;
Для решения применим правило '''SRPT-FM''' (Shortest Remaining Processing Time on Fastest Machine), которое предлагает класть работу с наименьшим оставшемся временем обработки на самый быстрый доступный станок. Отсортируем работы по времени обработки в невозрастающем порядке так, что &amp;lt;tex&amp;gt;p_1 \ge p_2 \ge ... \ge p_n&amp;lt;/tex&amp;gt;. Отсортируем станки по скорости обработки в невозрастающем порядке, так чтобы &amp;lt;tex&amp;gt;v_1 \ge v_2 \ge ... \ge v_m&amp;lt;/tex&amp;gt;. Далее назначаем &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt;-ю работу на станок &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt; (1-й по скорости станок) на время &amp;lt;tex&amp;gt;t_1 = \cfrac{p_n}{v_1}&amp;lt;/tex&amp;gt;, то есть пока она полностью не выполнится. Теперь назначим &amp;lt;tex&amp;gt;n-1&amp;lt;/tex&amp;gt; работу сначала станок &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt; на время &amp;lt;tex&amp;gt;t_1&amp;lt;/tex&amp;gt;, а затем на время от &amp;lt;tex&amp;gt;t_1&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;t_2 \ge t_1&amp;lt;/tex&amp;gt; на станок &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;, пока она не завершится. С &amp;lt;tex&amp;gt;n-2&amp;lt;/tex&amp;gt; работой поступаем аналогично, сначала она &amp;lt;tex&amp;gt;t_1&amp;lt;/tex&amp;gt; времени выполняется на станке &amp;lt;tex&amp;gt;M_3&amp;lt;/tex&amp;gt;, затем &amp;lt;tex&amp;gt;t_2 - t_1&amp;lt;/tex&amp;gt; времени на станке &amp;lt;tex&amp;gt;M_2&amp;lt;/tex&amp;gt;, и, начиная с &amp;lt;tex&amp;gt;t_2&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;t_3 \ge t_2&amp;lt;/tex&amp;gt;, на станке &amp;lt;tex&amp;gt;M_1&amp;lt;/tex&amp;gt;. Также поступаем со всеми оставшимися работами.&lt;br /&gt;
&lt;br /&gt;
=== Псевдокод ===&lt;br /&gt;
 a = 0&lt;br /&gt;
 p[] // массив времен обработки работ отсортированный в невозрастающем порядке&lt;br /&gt;
 v[] // массив скоростей обработки станков отсортированный в невозрастающем порядке&lt;br /&gt;
 '''while''' p[1] &amp;gt; 0&lt;br /&gt;
    Находим наибольший i такой, что p[i] &amp;gt; 0&lt;br /&gt;
    t = p[i] / v[1]&lt;br /&gt;
    '''for''' j = i '''down to''' k = max(1, i - m + 1)&lt;br /&gt;
        Назначаем работу j на станок &amp;lt;tex&amp;gt;M_{1+i-j}&amp;lt;/tex&amp;gt; на время от a до a + t&lt;br /&gt;
        p[j] = p[j] - t * v[1 + i - j]&lt;br /&gt;
    a = a + t&lt;br /&gt;
&lt;br /&gt;
Сложность алгоритма составляет &amp;lt;tex&amp;gt; \mathcal{O}(n\log{n} + mn)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
== Доказательство корректности алгоритма ==&lt;br /&gt;
{{Лемма&lt;br /&gt;
|statement=&lt;br /&gt;
Существует оптимальное расписание, в котором &amp;lt;tex&amp;gt;C_j \le C_k&amp;lt;/tex&amp;gt;, когда &amp;lt;tex&amp;gt;p_j \le p_k&amp;lt;/tex&amp;gt;, для всех &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
Рассмотрим расписание &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, где для некоторых &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; верно, что &amp;lt;tex&amp;gt;C_j &amp;gt; C_k&amp;lt;/tex&amp;gt;, но &amp;lt;tex&amp;gt;p_j \le p_k&amp;lt;/tex&amp;gt;. С помощью обмена частей обработки, полученной работами &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, мы можем изменить расписание &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt;, получив новое оптимальное расписание &amp;lt;tex&amp;gt;S'&amp;lt;/tex&amp;gt;, где обработка работ &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; завершается во времена &amp;lt;tex&amp;gt;C'_j \le C_k&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;C'_k = C_j&amp;lt;/tex&amp;gt; соответственно, при этом время завершения обработки остальных работ остается прежним. Тот факт, что в расписании &amp;lt;tex&amp;gt;S'&amp;lt;/tex&amp;gt; работа &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; заканчивается раньше &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, при этом не нарушая оптимальности расписания, свидетельствует о существовании расписания, описанного в условии леммы.&lt;br /&gt;
&lt;br /&gt;
Для построения расписания &amp;lt;tex&amp;gt;S'&amp;lt;/tex&amp;gt; из расписания &amp;lt;tex&amp;gt;S&amp;lt;/tex&amp;gt; введем следующие обозначения:&lt;br /&gt;
* &amp;lt;tex&amp;gt;p^1_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;p^1_k&amp;lt;/tex&amp;gt; {{---}} количество обработки, полученной одновременно &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, когда работа &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; была на более быстром станке или обе работы были на одинаковых станках.&lt;br /&gt;
* &amp;lt;tex&amp;gt;p^2_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;p^2_k&amp;lt;/tex&amp;gt; {{---}} количество обработки, полученной одновременно &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;, когда работа &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; была на более быстром станке.&lt;br /&gt;
* &amp;lt;tex&amp;gt;p^3_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;p^3_k&amp;lt;/tex&amp;gt; {{---}} количество обработки, полученной &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; до момента &amp;lt;tex&amp;gt;C_k&amp;lt;/tex&amp;gt; на непересекающихся участках времени.&lt;br /&gt;
* &amp;lt;tex&amp;gt;p^+_j&amp;lt;/tex&amp;gt; {{---}} количество обработки, полученной &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; после момента &amp;lt;tex&amp;gt;C_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Далее существуют два случая:&lt;br /&gt;
* Если &amp;lt;tex&amp;gt;p^+_j \le p^3_k&amp;lt;/tex&amp;gt;, то расписание &amp;lt;tex&amp;gt;S'&amp;lt;/tex&amp;gt; получается обменом обработки, полученной &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; после момента &amp;lt;tex&amp;gt;C_k&amp;lt;/tex&amp;gt; с частью обработки, полученной &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; не одновременно с &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Если &amp;lt;tex&amp;gt;p^+_j &amp;gt; p^3_k&amp;lt;/tex&amp;gt;, то для начала обмениваем всю обработку &amp;lt;tex&amp;gt;p^3_k&amp;lt;/tex&amp;gt; с частью &amp;lt;tex&amp;gt;p^+_j&amp;lt;/tex&amp;gt;, чтобы получить новое расписании, где &amp;lt;tex&amp;gt;C'_k = C_j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\tilde{p}^+_j = p^+_j - p^3_k&amp;lt;/tex&amp;gt; обработки &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; после момента &amp;lt;tex&amp;gt;C_k&amp;lt;/tex&amp;gt;. Пусть &amp;lt;tex&amp;gt;p^2_j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p^2_k&amp;lt;/tex&amp;gt; представлены числом &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; непересекающихся временных интервалов длинной &amp;lt;tex&amp;gt;t_i&amp;lt;/tex&amp;gt; с &amp;lt;tex&amp;gt;v^i_j&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;v^i_k&amp;lt;/tex&amp;gt; {{---}} скоростями станков, обрабатывающих &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; в интервал &amp;lt;tex&amp;gt;i&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p^{2,i}_j = v^i_j \cdot t_i&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;p^{2,i}_k = v^i_k \cdot t_i&amp;lt;/tex&amp;gt; {{---}} количество обработки, полученной соответвующей задачей за этот интервал. Так как &amp;lt;tex&amp;gt;p^1_j \ge p^1_k&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;p_j \le p_k&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;p^2_j + \tilde{p}^+_j \le p^2_k&amp;lt;/tex&amp;gt;. Следовательно существует такой &amp;lt;tex&amp;gt;\tilde{p}^{+,i}_j&amp;lt;/tex&amp;gt;, что верно:&amp;lt;br&amp;gt;&amp;lt;tex&amp;gt;\sum\limits_{i=1}^{T}{\tilde{p}^{+,i}_j} = \tilde{p}^+_j&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;p^{2,i}_j + \tilde{p}^{+,i}_j \le p^{2,i}_k&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;i = 1...T&amp;lt;/tex&amp;gt;&amp;lt;br&amp;gt;Для каждого &amp;lt;tex&amp;gt;i = 1...T&amp;lt;/tex&amp;gt; пусть &amp;lt;tex&amp;gt;t^i_j = \cfrac{\tilde{p}^{+,i}_j}{v^i_k - v^i_j}&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;t^i_k = t^i_j \cdot \cfrac{v^i_j}{v^i_k}&amp;lt;/tex&amp;gt;. Чтобы получить расписание &amp;lt;tex&amp;gt;S'&amp;lt;/tex&amp;gt; для каждого из &amp;lt;tex&amp;gt;T&amp;lt;/tex&amp;gt; интервалов нужно обменять:&amp;lt;br&amp;gt; 1) обработку, полученную в начале интервала работой &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; на более быстром станке, с обработкой &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt;, полученной на медленном станке, на интервалы &amp;lt;tex&amp;gt;t^i_k&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;t^i_j&amp;lt;/tex&amp;gt; соответственно&amp;lt;br&amp;gt;2) обработку &amp;lt;tex&amp;gt;\tilde{p}^{+,i}_j&amp;lt;/tex&amp;gt;, полученной &amp;lt;tex&amp;gt;j&amp;lt;/tex&amp;gt; после момента &amp;lt;tex&amp;gt;C_k&amp;lt;/tex&amp;gt;, с таким же количеством обработки, полученной работой &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; на более быстром станке в этот интервал сразу после момента &amp;lt;tex&amp;gt;t^i_k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{Теорема&lt;br /&gt;
|statement=&lt;br /&gt;
Расписание, построенное по принципу '''SRPT-FM''', оптимальное для задачи &amp;lt;tex&amp;gt; Q \mid pmtn \mid \sum C_i &amp;lt;/tex&amp;gt;&lt;br /&gt;
|proof=&lt;br /&gt;
В разработке&lt;br /&gt;
}}&lt;/div&gt;</summary>
		<author><name>46.183.217.186</name></author>	</entry>

	</feed>