Часто возникает необходимость возводить в большую степень либо число либо матрицу. Либо вычислять такую сумму 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)