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;
}

POJ 3150 Cellular Automaton

时间: 2024-10-07 17:56:53

POJ 3150 Cellular Automaton的相关文章

POJ 3150 Cellular Automaton(矩阵乘法+二分)

题目链接 题意 : 给出n个数形成环形,一次转化就是将每一个数前后的d个数字的和对m取余,然后作为这个数,问进行k次转化后,数组变成什么. 思路 :下述来自here 首先来看一下Sample里的第一组数据.1 2 2 1 2经过一次变换之后就成了5 5 5 5 4它的原理就是a0 a1 a2 a3 a4->(a4+a0+a1) (a0+a1+a2) (a1+a2+a3) (a2+a3+a4) (a3+a4+a0) 如果用矩阵相乘来描述,那就可以表述为1xN和NxN的矩阵相乘,结果仍为1xN矩阵a

poj 3150 Cellular Automaton(矩阵快速幂)

http://poj.org/problem?id=3150 大致题意:给出n个数,问经过K次变换每个位置上的数变为多少.第i位置上的数经过一次变换定义为所有满足 min( abs(i-j),n-abs(i-j) )<=d的j位置上的数字之和对m求余. 思路: 我们先将上述定义表示为矩阵 B =  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[i][j] = 表示i与j满足上述关系,B[i][j] = 0表示i与j不满足上述关系.根据这个

[POJ 3150] Cellular Automaton (矩阵快速幂 + 矩阵乘法优化)

Cellular Automaton Time Limit: 12000MS   Memory Limit: 65536K Total Submissions: 3048   Accepted: 1227 Case Time Limit: 2000MS Description A cellular automaton is a collection of cells on a grid of specified shape that evolves through a number of dis

POJ - 3150 :Cellular Automaton(特殊的矩阵,降维优化)

A cellular automaton is a collection of cells on a grid of specified shape that evolves through a number of discrete time steps according to a set of rules that describe the new state of a cell based on the states of neighboring cells. The order of t

POJ 3150 Cellular Automaton --矩阵快速幂及优化

题意:给一个环,环上有n块,每块有个值,每一次操作是对每个点,他的值变为原来与他距离不超过d的位置的和,问k(10^7)次操作后每块的值. 解法:一看就要化为矩阵来做,矩阵很好建立,大白书P157页有讲,大概为: [1 1 0 .. 0 1] [1 1 1 .. .. 0] ... [1 1 .. .. .. 1]  的循环矩阵,可以证明,循环矩阵的乘积还是循环矩阵,且循环矩阵的性质: a[i][j] = a[i-1][j-1] (循环的) ,所以,我们每次矩阵相乘只需要算出第一行,余下的不需要

【POJ】3150 Cellular Automaton(矩阵乘法+特殊的技巧)

http://poj.org/problem?id=3150 这题裸的矩阵很容易看出,假设d=1,n=5那么矩阵是这样的 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 这是n^3的,可是n<=500,显然tle 我们观察这个n×n的矩阵,发现没一行都是由上一行向右移得到的. 而根据Cij=Aik×Bkj,我们可以发现,其实Bkj==Akj==Ai(j-k) 那么就可以降二维变一维,每一次只要算第一行即可,即Cj=Ak*Bj-k #includ

【poj 3150】Cellular Automaton 矩阵

题目:http://poj.org/problem?id=3150 Cellular Automaton 矩阵乘法+二分 Cellular Automaton Time Limit: 12000MS Memory Limit: 65536K Total Submissions: 3544 Accepted: 1428 Case Time Limit: 2000MS Description A cellular automaton is a collection of cells on a gri

UVA 1386 - Cellular Automaton(循环矩阵)

UVA 1386 - Cellular Automaton 题目链接 题意:给定一个n格的环,现在有个距离d,每次变化把环和他周围距离d以内的格子相加,结果mod m,问经过k次变换之后,环上的各个数字 思路:矩阵很好想,每个位置对应周围几个位置为1,其余位置为0,但是这个矩阵有500,有点大,直接n^3去求矩阵不太合适,然后观察发现这个矩阵是个循环矩阵,循环矩阵相乘的话,只需要保存一行即可,然后用n^2的时间就足够计算了 代码: #include <stdio.h> #include <

Uva 1386 - Cellular Automaton ( 矩阵乘法 + 循环矩阵 )

Uva 1386 - Cellular Automaton ( 矩阵乘法 + 循环矩阵 ) #include <cstdio> #include <cstring> #define CLR( a, b ) memset( a, b, sizeof(a) ) int MOD; #define MAX_SIZE 500 struct Mat { int n; LL mat[MAX_SIZE][MAX_SIZE]; Mat( int _n = 0 ) { n = _n; CLR( mat