「POJ3150」Cellular Automaton
Description
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 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 k d-steps.
Input
The first line of the input file contains four integer numbers n, m, d, and k (1 ≤ n ≤ 500, 1 ≤ m ≤ 1 000 000, 0 ≤ d < n⁄2 , 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 k d-steps.
Sample Input
1 2 3 4 5 6 7 |
<b>sample input #1</b> 5 3 1 1 1 2 2 1 2 <b>sample input #2</b> 5 3 1 10 1 2 2 1 2 |
Sample Output
1 2 3 4 5 |
<b>sample output #1</b> 2 2 2 2 1 <b>sample output #2</b> 2 0 0 2 2 |
题解
首先来看一下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矩阵
b = 1 2 2 1 2
a =
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 * a = 5 5 5 5 4
所以最终结果就是:a * (b^k)
复杂度是n^3logk,过不了
于是我们发现这个矩阵长得很奇葩,每一行都是上一行后移一位得到
所以我们每个矩阵可以变成一行,这样就可以少1个n
把原来的a[i][k]变成a[i-k]
然后就是快速幂。。。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
#include<iostream> #include<cstring> #include<cstdio> #define ll long long using namespace std; ll n,m,d,k; ll num[500],a[500],b[500]; void prll(ll a[]){for(ll i=0;i<n;i++)cout<<a[i]<<' ';cout<<endl;} void mul(ll a[],ll b[],ll ans[]) { ll t[500]; memset(t,0,sizeof(t)); for(ll i=0;i<n;i++) for(ll k=0;k<n;k++) if(i-k>=0)t[i]=(t[i]+(a[k]*b[i-k])%m)%m; else t[i]=(t[i]+(a[k]*b[i-k+n])%m)%m; for(ll i=0;i<n;i++)ans[i]=t[i]; } int main() { scanf("%d%d%d%d",&n,&m,&d,&k); for(ll i=0;i<n;i++)scanf("%d",&num[i]); for(ll i=0;i<=d;i++)a[i]=1; for(ll i=n-1;i>=n-d;i--)a[i]=1; b[0]=1; while(k) { if(k&1)mul(b,a,b); k>>=1; mul(a,a,a); } mul(num,b,num); prll(num); return 0; } |