POJ 3233
题目大意:
给定三个数n,m,k。
下面n行每行n个数
给定一个矩阵n*n的矩阵A
求S = A^1 + A ^2 +……+A^k答案对m取模
n的范围30,k的范围10^9,m的范围10^4。
这道题我一看就知道要用等比的性质,但奈何我不会啊0 0,所以退而求次用二分来做了。
首先我们要用到矩阵快速幂。
然后怎么求和呢
一个小技巧
当k为偶数时
S=A^1+A^2+……+A^k=(A^1+A^2+…+A^(k/2))*(1+A^(k/2))
注意这里的1指的是单位矩阵。
然后当k为奇数时只用加上一个A^K就可以了
详情见代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
using namespace std;
int n, m, k;
struct Mar{
int aa[40][40];
};
Mar a, res;
Mar cheng( Mar a, Mar b ) {
Mar c;
for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= n; j++ ) {
c.aa[i][j] = 0;
for ( int k = 1; k <= n; k++ )
c.aa[i][j]=(c.aa[i][j]+(a.aa[i][k]*b.aa[k][j])%m)%m;
}
return c;
}
Mar qpow( Mar a, int k ) {
Mar c;
for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= n; j++ )
if ( i == j ) c.aa[i][j] = 1;
else c.aa[i][j] = 0;
for( ; k; k >>= 1, a = cheng( a, a ) )
if ( k & 1 ) c = cheng( c, a );
return c;
}
void work( int k ) {
if ( k == 1 ) {
res = a;
return;
}
work(k/2);
Mar c = qpow(a, k/2);
for ( int i = 1; i <= n; i++ )
c.aa[i][i] ++;
res = cheng(res, c);
if (k % 2 != 0) {
Mar p = qpow(a, k);
for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= n; j++ )
res.aa[i][j] = (res.aa[i][j] + p.aa[i][j])%m;
}
}
int main() {
scanf( "%d%d%d", &n, &k, &m );
for ( int i = 1; i <= n; i++ )
for ( int j = 1; j <= n; j++ )
scanf( "%d", &a.aa[i][j] );
work(k);
for ( int i = 1; i <= n; i++,printf("\n") )
for ( int j = 1; j <= n; j++ )
printf("%d ", res.aa[i][j] );
return 0;
}
ok结束