《大白书》156页,LA3704(UVa 1386) 细胞自动机

来源:互联网 发布:裤哥大战淘宝店主 编辑:程序博客网 时间:2024/05/07 22:56

【问题描述】

  一个细胞自动机包含n个格子,每个格子的取值为0~m-1。给定距离d,则每次操作后每个格子的值将变为到它距离不超过d的所有格子在操作之前的值之和除以m的余数,其中i和j的距离为min{|i-j|,n-|i-j|}。给定n,m,d,k和自动机各格子的初始值,你的任务是计算k次操作以后各格子的值。

  如下图,n=5,m=3,d=1,一次操作将把图a变成图b。比如,与格子3距离不超过1的格子(即格子2,3,4)在操作之前的值分别是2,2,1,因此从 操作后格子3的值为(2+2+1)mod 3=2。
     

【输入格式】

  第一行包含4个整数n,m,d,k。第二行包含n个0..m-1的整数,即各格子的初始值。

【输出格式】

  输出一行,包含n个0..m-1的整数,即k次操作后各格子的值。

【输入样例】

【样例1】
 5 3 1 1
 1 2 2 1 2

【样例2】
 5 3 1 10
 1 2 2 1 2

【输出样例】

【样例1】
 2 2 2 2 1

【样例2】
 2 0 0 2 2

【数据范围】

1<=n<=500 1<=m<=10^6 0<=d

一开始看到这道题感觉应该是一道很神奇的暴力优化题,结果一看数据,果断放弃我这颗暴力的心。这道题真正的做法是用矩阵优化线性递推,来达到有2分快速幂的效果很好的把有关递推次数的时间复杂度转化到矩阵操作上,主要针对次数多递推关系不多的递推式(这种式子一般的递推准爆)。现在有了知识的基础再看这道题简直是显然,列好矩阵分分钟就搞定了。详细代码如下:
#include<cstdlib>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int maxn=505;int mod;struct mat{    ll v[maxn][maxn];    int m,n;    mat()    {        memset(v,0,sizeof(v));        m=n=0;    }    friend mat operator*(mat a,mat b)    {        mat c;        c.n=a.n;c.m=b.m;        for(int j=1;j<=b.m;j++)        for(int k=1;k<=a.m;k++)        c.v[1][j]=(c.v[1][j]+a.v[1][k]*b.v[k][j])%mod;        for(int i=2;i<=c.n;i++)        {            c.v[i][1]=c.v[i-1][b.m];            for(int j=2;j<=b.m;j++)            c.v[i][j]=c.v[i-1][j-1];        }        return c;    }}a,b;mat qkpow(mat y,ll x){    mat t,c;    c.m=c.n=y.m;    for(int i=1;i<=c.m;i++) c.v[i][i]=1;    t=y;    while(x)    {        if (x&1) c=c*t;        x=x>>1;        t=t*t;    }    return c;}int read(){    int x=0;    char ch=getchar();    while(ch<'0'||ch>'9') ch=getchar();    while(ch>='0'&&ch<='9')    {        x=x*10+ch-'0';        ch=getchar();    }    return x;}mat work(mat a,mat b){    mat c;    c.n=a.n;c.m=b.m;    for(int i=1;i<=c.n;i++)    for(int j=1;j<=b.m;j++)    for(int k=1;k<=a.m;k++)      c.v[i][j]=(c.v[i][j]+a.v[i][k]*b.v[k][j])%mod;    return c;}int main(){    //freopen("in.txt","r",stdin);    //freopen("out.txt","w",stdout);    int n=read();mod=read();    int d,T;    d=read();T=read();    a.m=1;    a.n=n;    for(int i=1;i<=n;i++) a.v[i][1]=read();    b.n=b.m=n;    for(int j=1;j<=d+1;j++) b.v[1][j]=1;    for(int j=n;j>n-d;j--) b.v[1][j]=1;    for(int i=2;i<=n;i++)    {        b.v[i][1]=b.v[i-1][n];        for(int j=2;j<=n;j++)        b.v[i][j]=b.v[i-1][j-1];    }    b=qkpow(b,T);    a=work(b,a);    for(int i=1;i<=n;i++)    printf("%d ",a.v[i][1]);    return 0;}
1 0
原创粉丝点击