您的位置:首页 > 其它

poj3150 Cellular Automaton(矩阵快速幂)

2016-07-25 18:38 281 查看
对于样例:

5311

12212

使得

a = {1 2 2 1 2};

b = {

1 1 0 0 1

1 1 1 0 0

0 1 1 1 0

0 0 1 1 1

1 0 0 1 1

}

变换一次,矩阵相乘 a * b = 5 5 5 5 4;各项对取余就是结果;

如果变换k次,结果就是a×(b^k);所以用矩阵快速幂计算b^n;

但是n×n的矩阵会超时啊,而且要long long[500+][500+],数组太大,连本地都开不开。

但是矩阵b比较对称,可以发现

b^1 =

[1, 1, 0, 0, 1]

[1, 1, 1, 0, 0]

[0, 1, 1, 1, 0]

[0, 0, 1, 1, 1]

[1, 0, 0, 1, 1]

b^2 =

[3, 2, 1, 1, 2]

[2, 3, 2, 1, 1]

[1, 2, 3, 2, 1]

[1, 1, 2, 3, 2]

[2, 1, 1, 2, 3]

b^3 =

[7, 6, 4, 4, 6]

[6, 7, 6, 4, 4]

[4, 6, 7, 6, 4]

[4, 4, 6, 7, 6]

[6, 4, 4, 6, 7]

b^4 =

[19, 17, 14, 14, 17]

[17, 19, 17, 14, 14]

[14, 17, 19, 17, 14]

[14, 14, 17, 19, 17]

[17, 14, 14, 17, 19]

第i行是第i-1行向右平移一位。所以计算和存储都只关于第一行就行了。

数据较大,取余太多,用时就比较多,尽量少取余。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
#include<queue>
#include<vector>
#define LL long long
#define maxn 550

using namespace std;
int MOD,N;
struct Mat{
LL at[maxn];
int n;
Mat(){n=N;}
};
Mat mul(const Mat &a,const Mat &b)
{
Mat t;
memset(t.at,0,sizeof(t.at));
int p=0;
for(int i=0;i<a.n;++i)
{
for(int j=0;j<a.n;++j)
{
if(p==a.n)p=0;
t.at[i]+=(a.at[j]*b.at[p++]);
}
p--;
t.at[i]%=MOD;
}
return t;
}
Mat _pow (Mat p,int k)
{
if(k==1)return p;
Mat e;
memset(e.at,0,sizeof(e.at));
e.at[0]=1;
if(k==0)return e;
while(k)
{
if(k&1)e=mul(e,p);
p=mul(p,p);
k>>=1;
}
return e;
}
int main()
{
LL arr[maxn];
int n,d,k;
while(~scanf("%d%d%d%d",&N,&MOD,&d,&k))
{
n=N;
Mat tmp;
memset(tmp.at,0,sizeof(tmp.at));
tmp.at[0]=1;
for(int i=1;i<=d;++i)
{
tmp.at[i]=1;
int pos=-i;
if(pos<0)pos+=n;
tmp.at[pos]=1;
}
tmp=_pow(tmp,k);
for(int i=0;i<n;++i)
{
scanf("%lld",&arr[i]);
}
int p=0;
for(int i=0;i<n;++i)
{
LL ans=0;
for(int j=0;j<n;++j)
{
if(p==n)p=0;
ans+=arr[j]*tmp.at[p++];
}
p--;
ans%=MOD;
if(i!=0)
printf(" ");
printf("%lld",ans);
}
printf("\n");
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  poj 矩阵快速幂