UVA - 12183 :Top Secret(N^2的循环矩阵乘法)
pro:N个数排成一圈。一次操作为,每个位置的数+=L*左+R*右,保留x为整数。 问S轮操作后每个位置的值。 N<=1000,S<=2^30,x<=9 。
sol:不难想到矩阵乘法,但是N为1000,显然普通的N^3矩阵乘法的复杂度不能AC。 不难发现这是经典的循环矩阵(第二行为第一行右移一格....依次),所以我们只需要求第一行的矩阵,其他每一行都可以在第一行找到对应的值。
(我的代码1500ms,VJ有神仙150ms,暂时不知道怎么搞的。
#include<bits/stdc++.h> #define ll unsigned long long #define rep(i,a,b) for(int i=a;i<=b;i++) using namespace std; const int maxn=1010; int Mod; int p[10]={1,10,100,1000,10000,100000,1000000,10000000 ,100000000,1000000000}; int tt[maxn][2],res[maxn][2]; void read(int &x){ x=0; char c=getchar(); while(c>'9'||c<'0') c=getchar(); while(c>='0'&&c<='9') { x=x*10+c-'0'; c=getchar(); } } void MOD(int &x){ if(x>=Mod) x-=Mod; } struct mat{ int mp[2][maxn],C; mat(){} mat(int c){ rep(i,1,1) rep(j,1,c) mp[i][j]=0; C=c; } mat friend operator *(mat a,mat b){ mat res(a.C); rep(k,1,a.C) rep(i,1,1) //循环矩阵,求第一行即可 if(a.mp[i][k]) rep(j,1,a.C){ int t=(j-k+a.C+1)%a.C; if(t==0) t=a.C; MOD(res.mp[i][j]+=1LL*a.mp[i][k]*b.mp[1][t]%Mod); } return res; } mat friend operator ^(mat a,int x){ mat res(a.C); rep(i,1,1) res.mp[i][i]=1; while(x){ if(x&1) res=res*a; a=a*a; x>>=1; } return res; } }; int main() { int T,N,L,R,S,X; scanf("%d",&T); while(T--){ read(N); read(S); read(L); read(R); read(X); Mod=p[X]; mat a(N),base(N); rep(i,1,N) read(tt[i][1]),res[i][1]=0; rep(i,1,1) { base.mp[i][i-1==0?N:i-1]=L; base.mp[i][i+1==N+1?1:i+1]=R; base.mp[i][i]=1; } base=(base^S); rep(k,1,N) rep(i,1,N) rep(j,1,1){ int t=(k-i+N+1)%N; if(t==0) t=N; MOD(res[i][j]+=1LL*base.mp[1][t]*tt[k][j]%Mod); } rep(i,1,N-1) printf("%d ",res[i][1]); printf("%d\n",res[N][1]); } return 0; }
It is your time to fight!