组合数学:D - Cellular Automaton 求矩阵相乘

来源:互联网 发布:淘宝网摩托车专卖区 编辑:程序博客网 时间:2024/04/28 17:15

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 the cellular automaton is the number of cells it contains. Cells of the automaton of order n are numbered from 1 to n.

The order of the cell is the number of different values it may contain. Usually, values of a cell of order m are considered to be integer numbers from 0 to m − 1.

One of the most fundamental properties of a cellular automaton is the type of grid on which it is computed. In this problem we examine the special kind of cellular automaton — circular cellular automaton of order n with cells of order m. We will denote such kind of cellular automaton as n,m-automaton.

A distance between cells i and j in n,m-automaton is defined as min(|i − j|, n − |i − j|). A d-environment of a cell is the set of cells at a distance not greater than d.

On each d-step values of all cells are simultaneously replaced by new values. The new value of cell i after d-step is computed as a sum of values of cells belonging to the d-enviroment of the cell i modulo m.

The following picture shows 1-step of the 5,3-automaton.

The problem is to calculate the state of the n,m-automaton after kd-steps.

Input

The first line of the input file contains four integer numbers nmd, and k (1 ≤ n ≤ 500, 1 ≤ m ≤ 1 000 000, 0 ≤ d < n2 , 1 ≤ k ≤ 10 000 000). The second line contains n integer numbers from 0 to m − 1 — initial values of the automaton’s cells.

Output

Output the values of the n,m-automaton’s cells after kd-steps.

Sample Input

sample input #1 5 3 1 11 2 2 1 2 sample input #2 5 3 1 101 2 2 1 2

Sample Output

sample output #1 2 2 2 2 1 sample output #2 2 0 0 2 2

题目大意:一个元胞中包含若干细胞,每个细胞都有初始value值,题目定义了一个细胞距离,细胞i、j之间的距离d=min(|i-j|,n-|i-j|),称与细胞i距离不超过d的所有细胞(包括该细胞本身)的集合为细胞i的d-environment,经过一个d-steps变换后,元胞中每一个细胞的值变为该细胞d-environment内所有细胞value值总和模上m,最后求经过k个d-steps变换后,元胞中每个细胞的最终值。分析:给定一个元胞后,与某个细胞i距离不超过d的所有细胞是确定,例如样例中与1号细胞的1-environment集合为细胞5、细胞1、细胞2,则经过一个1-step后,细胞1中的值为(value[1]*1+value[2]*1+value[3]*0+value[4]*0+value[5]*1),这样应该很容易想到矩阵,样例1一个d-step对应的系数矩阵为:1 1 0 0 11 1 1 0 00 1 1 1 00 0 1 1 11 0 0 1 1若将元胞的初始value存成一个行向量,对元胞进行一个d-steps变换只要将该行向量乘以这个系数矩阵,这样得到一个新的行向量,即一个新的元胞,所以k个d-steps变换就乘k次系数矩阵(所有值都要摸m),根据矩阵的结合性,可以先算系数矩阵的k次方,最后乘上初始value矩阵,至此题目的大体思路就是这样,但是k很大,做k次矩阵乘法要二分,将复杂度降到n^3*logk,n最大是500,500^3任然很大,观察系数矩阵发现系数矩阵及它的任意次方必是对称矩阵并且是循环矩阵,x[i][j]=x[i+1][j+1],根据这些性质每一次矩阵相乘只需计算一行,然后其余部分都能得出,这样该题最终的复杂度为(n^2)*logk。


这题好可怕,看了好久矩阵的乘法啊……直接算超时,得一点一点优化……有了个大神些许代码就搞定了,真是太膜拜了,更膜拜的是,看他的代码看了两个半小时才理解一半啊,矩阵想想本来是二维的,他硬是一维还有用二分给搞定了,膜拜啊!!!羡慕羡慕

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<string>#include<cmath>#include<set>#include<vector>#include<stack>#define mem(a,b) memset(a,b,sizeof(a))using namespace std;typedef long long ll;int n,m,d,k;long long a[501],b[501];void cmp(long long a[],long long b[]){    int i,j;    long long c[501];    for(i=0; i<n; ++i)        for(c[i]=j=0; j<n; ++j)            c[i]+=a[j]*b[i>=j?(i-j):(n+i-j)];    for(i=0; i<n; b[i]=c[i++]%m);}int main(){    int i,j;    scanf("%d%d%d%d",&n,&m,&d,&k);    for(i=0; i<n; ++i)        scanf("%lld",&b[i]);    for(a[0]=i=1; i<=d; ++i)        a[i]=a[n-i]=1;    while(k)    {        if(k&1) cmp(a,b);  //因为最后k为1,而且最后总要乘初始矩阵        cmp(a,a);        k>>=1;    }    for(i=0; i<n-1; ++i)        printf("%lld ",b[i]);    printf("%lld\n",b[i]);    return 0;}