对于样例:
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");
}
}