朴素的矩阵乘法O(n^3)会超时。
但是因为这个矩阵是循环矩阵,根据循环矩阵的性质:
循环矩阵*循环矩阵=循环矩阵
所以只用算出第一行,然后根据循环矩阵的性质就可以递推出下一行,进而得到整个循环矩阵。
时间复杂度降为O(n^2)。
如果遇到一些模板题却超时就要好好想一想这道题跟模板题到底哪里不一样了,进而才能发现优化的方法。
很多东西都是靠想出来的。
代码
#include<bits/stdc++.h>
#define f(i) for(ll i=0;i<N;i++)
using namespace std;
typedef long long ll;
ll N,M,D,K;
vector<ll> mul(vector<ll>A,vector<ll>B)
{
vector<ll>ret(N*N);
f(j) f(k)
ret[j]=(ret[j]+A[k]*B[k*N+j]%M)%M;
for(int i=1;i<N;i++) f(j)
ret[i*N+j]=ret[(i-1)*N+((j-1)%N+N)%N];
return ret;
}
vector<ll> mp(vector<ll>x,ll n)
{
vector<ll>ret(N*N);
f(i) ret[i*N+i]=1;
while(n)
{
if(n&1) ret=mul(ret,x);
x=mul(x,x);
n>>=1;
}
return ret;
}
int main()
{
while(scanf("%lld %lld %lld %lld",&N,&M,&D,&K)==4)
{
vector<ll>ji(N*N),chu(N);
f(i) scanf("%lld",&chu[i]);
f(i) for(ll j=-D;j<=D;j++)
ji[i*N+((i+j)%N+N)%N]=1;
//f(i){f(j)printf("%lld ",ji[i*N+j]);puts("");}
ji=mp(ji,K);
//puts("**********");f(i){f(j)printf("%lld ",ji[i*N+j]);puts("");}puts("**********");
f(i){ll ans=0;f(j)
ans=(ans+chu[j]*ji[i*N+j]%M)%M;
printf("%lld%c",ans,i==N-1?'\n':' ');
}
}
return 0;
}