UVA

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
",res[N][1]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hua-dong/p/10996567.html