首页 > 代码库 > POJ 3150 Cellular Automaton

POJ 3150 Cellular Automaton

矩阵的题就是这么伤脑筋啊~~    sad……


题目大意:

一个环上有n个数,定义一种操作将它和它距离小于d的数加和再模m。每次操作刷新所有数。问k次之后都将变成什么数?


解题思路:

矩阵快速幂加速递推。

按照正常思路第i次操作是基于第i-1次操作完成的,也就是说要完成第i次操作需要先完成第i-1次。

但是用于矩阵之后可以直接推出第i次与第一次之间是什么关系。

这个矩阵是可以通过矩阵快速幂得出的。取模也是顺带的~


如果你注意关系矩阵的建立的话,你会发现这么一个规律。对于d=1来说:

b^1 =
[1, 1, 0, 0, 1]
[1, 1, 1, 0, 0]
[0, 1, 1, 1, 0]
[0, 0, 1, 1, 1]
[1, 0, 0, 1, 1]
b^2 =
[3, 2, 1, 1, 2]
[2, 3, 2, 1, 1]
[1, 2, 3, 2, 1]
[1, 1, 2, 3, 2]
[2, 1, 1, 2, 3]
b^3 =
[7, 6, 4, 4, 6]
[6, 7, 6, 4, 4]
[4, 6, 7, 6, 4]
[4, 4, 6, 7, 6]
[6, 4, 4, 6, 7]
b^4 =
[19, 17, 14, 14, 17]
[17, 19, 17, 14, 14]
[14, 17, 19, 17, 14]
[14, 14, 17, 19, 17]
[17, 14, 14, 17, 19]


也就是说我们只需要存第一行就行了。每次矩阵乘法也只需要得出第一行就行了。



下面是代码:

#include <set>
#include <map>
#include <queue>
#include <math.h>
#include <vector>
#include <string>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>

#define eps 1e-7
#define pi acos(-1.0)
#define inf 107374182
#define inf64 1152921504606846976
#define lc l,m,tr<<1
#define rc m + 1,r,tr<<1|1
#define iabs(x)  ((x) > 0 ? (x) : -(x))
#define clear1(A, X, SIZE) memset(A, X, sizeof(A[0]) * (SIZE))
#define clearall(A, X) memset(A, X, sizeof(A))
#define memcopy1(A , X, SIZE) memcpy(A , X ,sizeof(X[0])*(SIZE))
#define memcopyall(A, X) memcpy(A , X ,sizeof(X))
#define max( x, y )  ( ((x) > (y)) ? (x) : (y) )
#define min( x, y )  ( ((x) < (y)) ? (x) : (y) )

using namespace std;


struct node
{
    long long matrix[505];
}a,temp;

int n,m,d,k;

node does(node a,node b)
{
    node c;
    clearall(c.matrix,0);
    int p;
    for(int i=0;i<n;i++)
    {
        p=(n-i)%n;
        for(int j=0;j<n;j++)
        {
            c.matrix[i]+=a.matrix[j]*b.matrix[p++];
            if(p==n)p=0;
        }
        c.matrix[i]%=m;
    }
    return c;
}
void mul(int k)
{
    clearall(temp.matrix,0);
    temp.matrix[0]=1;
    while(k)
    {
        if(k&1)temp=does(temp,a);
        a=does(a,a);
        k>>=1;
    }
}
int main()
{
    long long num[505],ans[505];
    int p;
    while(scanf("%d%d%d%d",&n,&m,&d,&k)!=EOF)
    {
        clearall(ans,0);
        for(int i=0;i<n;i++)
        {
            scanf("%lld",&num[i]);
        }
        for(int i=0;i<n;i++)
        {
            if(i<=d||n-i<=d)a.matrix[i]=1;
            else a.matrix[i]=0;
        }
        mul(k);
        for(int i=0;i<n;i++)
        {
            if(i!=0)printf(" ");
            p=(n-i)%n;
            for(int j=0;j<n;j++)
            {
                ans[i]+=temp.matrix[p++]*num[j];
                if(p==n)p=0;
            }
            printf("%lld",ans[i]%m);
        }
        puts("");
    }
    return 0;
}