Poj 3233题意要求矩阵S=A+A^2+A^3+...+A^k mod m,可以用二分的方法
首先矩阵相乘用一次二分,然后求和再用一次二分,两次二分。
其中,矩阵相乘二分: A^2k=A^k*A^k,
A^(2k+1)=A^k*A^k*A.
求和二分: A+A^2+A...+A^(2k+1) = A+A^2+...+A^k+A^(k+1)+A^(k+1)*(A+A^2+...+A^k).
A+A^2+...+A^2k = A+A^2+...+A^k+A^k*(A+A^2+...+A^k).
我的代码:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
int n,m,k;
struct DATA
{
int a[32][32];
};
DATA point;
DATA mul(DATA a,DATA b)
{
int i,j,k;
DATA c;
memset(c.a,0,sizeof(c.a));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(a.a[i][j])//在这里优化了一下,仔细研究下
for(k=0;k<n;k++)
{
c.a[i][k]+=a.a[i][j]*b.a[j][k];
c.a[i][k]=c.a[i][k]%m;
}
}
return c;
}
DATA mu(DATA a,int y)
{
int i,j;
DATA c;
memset(c.a,0,sizeof(c.a));
for(i=0;i<n;i++)
c.a[i][i]=1;
while(y>0)
{
if(y&1)
c=mul(c,a);
a=mul(a,a);
y>>=1;
}
return c;
}
DATA aad(DATA a,DATA b)
{
int i,j;DATA c;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
c.a[i][j]=a.a[i][j]+b.a[i][j];
c.a[i][j]=c.a[i][j]%m;
}
return c;
}
DATA work(DATA a,int j)
{
DATA bb,cc,dd;int i;
if(j==1)
return a;
cc=work(a,j/2);
if(j&1)
{
dd=mu(a,j/2+1);
bb=mul(cc,dd);
dd=aad(dd,bb);
dd=aad(dd,cc);
return dd;
}
else
{
dd=mu(a,j/2);
bb=mul(cc,dd);
bb=aad(cc,bb);
return bb;
}
}
int main()
{int i,j,t;
scanf("%d%d%d",&n,&k,&m);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
scanf("%d",&point.a[i][j]);
point=work(point,k);
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{if(j==n-1)
printf("%d\n",point.a[i][j]%m);
else
printf("%d ",point.a[i][j]%m);
}
return 0;
}