Часто возникает необходимость возводить в большую степень либо число либо матрицу. Либо вычислять такую сумму A^1 + A^2 + ... A^n.
Для того чтобы все это сделать за достаточно быстрое время (возвести в степень за O(log(n)) умножений, а посчитать сумму за O(log^2(n)) умножений), рассмотрим такие выражения:
A^{2q} = (A^q)^2 и A^{2q+1} = A^{2q} * A
A^1+A^2+...+A^{2q} = (E+A^{q})*(A^1+A^2+...+A^{q}) и A^1+A^2+...+A^{2q+1} = (A^1+A^2+...+A^{2q}) *A+ A^1
Вот код:
Код:
public class Pow {
long pow(long n, long pow){
long res = 1;
while(n != 0){
if((pow&1) != 0){
res*=n;
}
n*=n;
pow>>=1;
}
return res;
}
long psum(long n, long pow){
if(pow == 0){
return 1;
}
if(pow == 1){
return n;
}
if(pow % 2 == 0){
return psum(n, pow / 2) * (1 + pow(n, pow/2));
}else{
return n + (psum(n, pow-1) * n);
}
}
long[][] mpsum(long[][] a, long k)
{
if (k == 0) {
return munit(a.length);
}
if (k == 1) {
return a;
}
if (k % 2 == 0)
{
return mmul(mpsum(a, k / 2), madd(munit(a.length), mpow(a, k / 2)));
}
else
{
return madd(a, mmul(mpsum(a, k - 1), a));
}
}
long[][] mpow(long[][] a, long k){
if (k == 0){
return munit(a.length);
}
else if (k % 2 == 0){
return mpow(mmul(a, a), k / 2);
}
else{
return mmul(a, mpow(a, k - 1));
}
}
long[][] mmul(long[][] a, long[][] b){
long[][] c = new long[a.length][b[0].length];
for (int i = 0; i < a.length; ++i){
for (int j = 0; j < b[0].length; ++j){
long z = 0;
for (int k = 0; k < a[0].length; ++k){
z += a[i][k] * b[k][j];
}
c[i][j] = z;
}
}
return c;
}
private long[][] madd(long[][] a, long[][] b){
long[][] c = new long[a.length][a[0].length];
for (int i = 0; i < a.length; ++i){
for (int j = 0; j < a[0].length; ++j){
c[i][j] = (a[i][j] + b[i][j]);
}
}
return c;
}
long[][] munit(int size){
long[][] res = new long[size][size];
for (int i = 0; i < size; ++i)
res[i][i] = 1;
return res;
}
}Отредактировано atimofeyev (2009-01-08 20:23:02)