Применение умножения матриц и быстрого возведения в степень

advertisement
Применение умножения матриц и быстрого возведения в степень
и линейные последовательности в олимпиадных задачах по
информатике.
2012.03.17
Общая рабочая тетрадь.
НЕ МУДРИТЬ!!! - см. KISS.
Умножение матриц
Type arr=array[1..100,1..100] of integer;
rec=record c:arr; nr,nc,z:longint; end;
Function mul(a,b:rec):rec;
Var t:rec;
Begin
if a.nc<>b.nr then begin mul.z:=-1; exit; end;
t.n:=a.n; t.m:=b.m;
for i:=1 to a.nr do
for j:=1 to b.nc do t.c[i,j]:=0;
for i:=1 to a.nr do
for j:=1 to b.nc do
for k:=1 to a.nc do t.c[i.j]:=t.c[i,j]+a.c[i,k]*b.c[k,j];
mul:=t;
end;
Возведение в степень вычисляем за O(log n) умножений матриц.
Числа Фибоначчи и обобщения
P - простое число около 10^9.
f[0] = f[1] = 1;
f[k] = ( f[k-1]+f[k-2] ) mod P.
fib[n]
=
fib[n-1]
X
=
Y
1
1
1
0
a
b
c
d
*
fib[n-1]
fib[n-2]
*
A
B
X = Aa+Bb
Y = Ac+Bd
f[k] = ( 3 * f[k-1]+f[k-2] ) mod P.
f[k-1] = 1 * f[k-1]
fib[n]
=
fib[n-1]
3
1
1
0
*
fib[n-1]
fib[n-2]
f[0]=f[1]=f[2]=1
f[k]=f[k-1]+f[k-2]+f[k-3];
f[n]
=
1
1
1
*
f[n-1]
f[n-1]
1
0
0
f[n-2]
f[n-2]
0
1
0
f[n-3]
Матрицы только квадратные. Ключевой момент - быстрое возведение матриц в степень, а в степень можно возводить
только квадратные матрицы.
Быстрое построение матриц
f[n]
=
?*f[n-1]
?*f[n-2]
?*f[n-3]
*
f[n-1]
f[n-1]
?*f[n-1]
?*f[n-2]
?*f[n-3]
f[n-2]
f[n-2]
?*f[n-1]
?*f[n-2]
?*f[n-3]
f[n-3]
Прикладываем правый столбик к строкам и проставляем коэффиенты по формуле либо копируем, когда член нужен просто
для вычисления предыдущего.
f[n] = 5*f[n-1]+7*f[n-2]+3*f[n-3]
f[n]
=
5*f[n-1]
7*f[n-2]
3*f[n-3]
*
f[n-1]
1*f[n-1]
0*f[n-2]
0*f[n-3]
f[n-2]
f[n-2]
0*f[n-1]
1*f[n-2]
0*f[n-3]
f[n-3]
Пропущенные члены
f[n]=f[n-1]+5*f[n-3]
f[n]
=
1
0
5
*
f[n-1]
f[n-1]
1
0
0
f[n-2]
f[n-2]
0
1
0
f[n-3]
Берем все пропущенные члены тоже!! НЕ МУДРИТЬ!
Свободный член
f[n]=2*f[n-1] + 3*f[n-2] + 5
f[n]
=
2
3
5
f[n-1]
1
0
0
f[n-2]
1
0
0
1
1
Несколько последовательностей
f[n]=f[n-1]+3*g[n-1]
g[n]=2*f[n-1]+g[n-1]
*
f[n-1]
f[n-1]
f[n]
=
g[n]
1
3
2
1
*
f[n-1]
g[n-1]
f[n]=5*f[n-1]+3*g[n-1]+2*g[n-2]
g[n]=2*f[n-1]+g[n-1]+5*g[n-2]
f[n]
=
*
f[n-1]
5
3
2
g[n]
2*f[n-1]
1*g[n-1]
5*g[n-2]
g[n-1]
g[n-1]
0*f[n-1]
1*g[n-1]
0*g[n-2]
g[n-2]
Как нам получить g[n-1] из f[n-1], g[n-1] и g[n-2]? СКОПИРОВАТЬ!
Двигаемся по одному шагу.
f[n]=5*h[n-1]+g[n-2]+f[n-3]+1
g[n]=3*h[n-2]+9
h[n]=7*g[n-1]+3*g[n-2]+3*f[n-1]+4*h[n-1]
Если есть свободный член, то в двух столбиках дописывает 1.
f[n]
=
0
0
1
0
1
5
0
1
f[n-1]
1
0
0
0
0
0
0
0
f[n-2]
f[n-2]
0
1
0
0
0
0
0
0
f[n-3]
g[n]
0
0
0
0
0
0
3
9
g[n-1]
g[n-1]
0
0
0
1
0
0
0
0
g[n-2]
h[n]
3
0
0
7
3
4
0
0
h[n-1]
h[n-1]
0
0
0
0
0
1
0
0
h[n-2]
1
0
0
0
0
0
0
0
1
1
Зависимость от n-го члена
f[n]=g[n-1]+2*g[n-2]+f[n-1]
g[n]=3*g[n-2] + 3*f[n]
Нужно выражать, быстрее это делать в самой матрице.
*
f[n-1]
f[n]
=
1
1
2
*
f[n-1]
g[n]
3
3
3+2*3
g[n-1]
g[n-1]
0
1
0
g[n-2]
ds
f[n]=2*g[n]+2*g[n-1]+f[n-1]
g[n]=3*f[n]+3*g[n-1] + 3*f[n-1]
Возможно стоит просто решить систему линейных уравнений?
Возможно противоречие и т.д. - это уже другая тема.
В какую степень возводить?
f[0] = f[1]=1
f[n] = f[n-1] + f[n-2]
fib[n]
=
fib[n-1]
1
1
1
0
*
fib[n-1]
fib[n-2]
В какую степень нужно возвести матрицу?
Для n=k в какую степень нужно возвести матрицу M и где взять fib[n]?
fib[n]
=
fib[n-1]
S(n)=M^x * S(y)
fib[n]=S(n)[z] (z=0 или 1)
Чему равны x,y,z?
x=n-1
y=1
z=0
S(1)= {fib[1], fib[0]}
S(2)=M^1*S(1)
====
А если нужно посчитать fib[0]?
Просто берем, если задано.
S(n) - столбик из 2-х ел
M
=
1
1
1
0
====
f[0]=f[1]=f[2]=1
f[n]=S(n)[0] * M^(n-2) * S(2)
Ориентируемся по первым членам.
Вычислительная сложность
f[0] = f[1]=1
f[n] = f[n-1] + f[n-2]
O(log2(n)*8+8)=O(log2(n))
В общем случае O(log_k(n))=O(log_n(n)). потому что log_k1(n)/log_k2(n)=const
====
f[n]=5*h[n-1]+g[n-2]+f[n-3]+1
g[n]=3*h[n-2]+9
h[n]=7*g[n-1]+3*g[n-2]+3*f[n-1]+4*h[n-1]
O(log2(n)*8^3)=O(log2(n))
Если константа-размерность матрицы небольшая , то ею можно пренебречь.
Арифметическая прогрессия
s(n)=1+2+...+n
Как посчитать?
s=(n*n+n)/2
O(1)
P-большое простое около 10^9
s(n)=(1+...+n) mod P
s=(((((n mod P)*(n mod P)) mod P + n mod P) mod P) * ((2^(p-2)) mod P)) mod P
2^(p-2)=2^(-1)*mod P
Мы сейчас не рассматриваем проблемы с переполением.
O(log2(p))
K-большое не-простое число около 10^9
Проблема - не всегда существует обратное для непростого К.
Пример: K=4 => 2^(4-2)=4 => 4 mod 4 = 0. 0*2 <> 1.
s(n)=s(n-1)+f(n); - зависящее от n, но выражаемо.
f(n)=f(n-1)+1
s(0)=0
f(0)=0
Преимущество матриц - используется только * и + - можно по любому не
обязательно простому модулю работать.
НО! Матрицы хорошо работают только для линейных соотношений.
O(log2(n))
========
s(n)=1+....+n
p(n)=s(1)+....+s(n)
s[n]=s[n-1]+f[n];
f[n]=f[n-1]+1=n
p[n]=p[n-1]+s[n]
f[n]
=
1
0
0
1
*
f[n-1]
s[n]
1
1
0
1
s[n-1]
p[n]
1
1
1
1
p[n-1]
1
0
0
0
1
1
Задача. Количество путей длины n на графе.
Существует ли путь в ориентированном графе длины n из вершины 0 в вершину k-1?
На входе матрица смежностей M.
Kil=(M^n) [0][k-1];
Если Kil>0, то существует.
Что делать в случае переполнения?
заменить умножение на AND
заменить сумму на OR.
Почему мы можем заменить * и + на AND и OR?
Мы умеем считать количество путей длины n.
===
Сколько существует путей длины <= n?
Размерность матрицы k.
v(i)[j] - количество путей длины j из 0 в i-ую вершину.
v(0)[n]
=
0
.
0
.
0
.
0
0
.
v(0)[n-1]
v(p,q)[n-1]
v(q)[n-1]
0
v(k-1)[n]
m(k-1,0)
.
.,,
,..
m(k-1,k-1)
0
v(k)
a(k-1)[n]
m(k-1,0)
...
...
...
m(k-1,k-1)
1
a(k-1)[n-1]
v(k-1)[n] - сколько путей длины ровно n.
a(k-1)[n] - количесво путей длины <= n из 0-ой вешині в k-1-ую.
a(k-1)[n] = a(k-1)[n-1] + v(k-1)[n].
=> дописываем 1 паременную.
Домашнее задание. Спросить у преподавателя по алгебре, когда в умножении
матриц * и + можно заменить на другие операции (например на AND и OR). На какие
другие операции можно заменять * и + ?
(Если повезет, то вам прочитают лекцию ;) )
Задача. Пирамидка.
Складываем пирамидку из шариков.
Если 1 слой - то 1 шарик, если 2 слоя - то 4 шарика (3 шарика, сверху 1), если 3 слоя, то
10 (6+3+1).
Сколько шариков в пирамидке высотой n?
В n-ом слое L(n) прибавляется n апельсинок по отношению к предыдующему.
L(n)=L(n-1)+n
S(n)=S(n-1)+L(n) - всего апельсинок.
=> строим матрицу и возводим в степень.
Сложность: O(log(n)).
Домашнее задание. Выучить метод неопределенных коефициентов, решить им
задачу про пирамидки за O(1). (Возможно поможет преподаватель по алгебре).
Вывод: увидели линейное соотношение - применяем умножение матриц!
Задачи на тему умножения матриц
TopCoder:
srm376_div1_500
srm377_div1_500
srm377_div1_950
srm403_div1_500
srm147_div1_1000 (not the best solution, but straight-forward)
srm428_div1_500
Рекомендации
* Больше практики, туров, соревнований.
* Избавляйтесь от Паскаля, используйте C++, C#, Java - за одно и работу сразу найдете ;)
Download