UVALive 3704 细胞自动机 矩阵快速幂

是时候要做做数学类的题目了

这属于比较简单的矩阵快速幂了,因为有个已知的矩阵循环的结论,所以为了节约时空,只需要保留一行即可,这个稍微有点难写,也不是难写,主要是注意细节。其他的矩阵快速幂一下即可

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 505
#define ll long long
using namespace std;
struct Mat
{
    ll mat[1][N];
}E,Z,O;
ll n,m,d,k;
void init()
{
    memset(E.mat,0,sizeof E.mat);
    for (int i=0;i<n;i++)
        E.mat[i][i]=1;
    memset(O.mat,0,sizeof O.mat);
    int tmp=0;
    for (int j=-d;tmp<2*d+1;j++,tmp++){
        if (j<0) j+=n;
        if (j>=n) j%=n;
        O.mat[0][j]=1;
    }
//    cout<<"!!!"<<endl;
//    for (int i=0;i<n;i++)
//        cout<<O.mat[0][i]<<" ";
//    cout<<endl;
}
Mat operator *(Mat a,Mat b)
{
    Mat c=Z;
    int i,j;
    for (i=0;i<n;i++){
        int cur=n-i;
        for (j=0;j<n;j++){ 
          if (cur>=n) cur%=n;//因为是循环矩阵,由第一行即可推得其他列的情况
          c.mat[0][i]+=a.mat[0][j]*b.mat[0][cur];
          cur++;
          if (c.mat[0][i]>=m) c.mat[0][i]%=m;
        }
    }
    return c;
}
Mat operator ^(Mat a,ll x)
{
    Mat c=E;
    for (;x;x>>=1){
        if (x&1){
            c=c*a;
        }
        a=a*a;
    }
    return c;
}
ll A[N],B[N];
int main()
{
    memset(Z.mat,0,sizeof Z.mat);
    while (scanf("%lld%lld%lld%lld",&n,&m,&d,&k)!=EOF)
    {
        init();
        Mat ans=O^k;
//        for (int i=0;i<n;i++)
//            cout<<ans.mat[0][i]<<" ~ ";
//        cout<<endl;
        for (int i=0;i<n;i++)
            scanf("%lld",&A[i]);
        for (int i=0;i<n;i++){
            int cur=n-i;
            B[i]=0;
            for (int j=0;j<n;j++){
                if (cur>=n) cur%=n;
                B[i]+=ans.mat[0][cur]*A[j];
                cur++;
                if (B[i]>=m) B[i]%=m;
            }
        }
        printf("%lld",B[0]);
        for (int i=1;i<n;i++)
            printf(" %lld",B[i]);
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/kkrisen/p/3687483.html