poj-3150-Cellular Automation
poj-3150-Cellular Automation
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 sample input #1 5 3 1 1 1 2 2 1 2 sample input #2 5 3 1 10 1 2 2 1 2 Sample Output sample output #1 2 2 2 2 1 sample output #2 2 0 0 2 2 Source |
17861637 | 3150 | Accepted | 408K | 3579MS | G++ | 1036B | 2017-11-19 20:48:11 |
元宝自动机。
经典的矩阵快速计算方法。
将有规律的矩阵简化为向量,由原来的 n^3 复杂度减小到 n^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,过不了
于是我们发现这个矩阵长得很奇葩,每一行都是上一行后移一位得到
所以我们每个矩阵可以变成一行
参考: https://www.cnblogs.com/iwtwiioi/p/3946211.html
// poj-3150 #include <cstdio> #include <cstring> const int MAXN = 500 + 10; long long n, m, d, k, num[MAXN], a[MAXN], b[MAXN], tmp[MAXN], ans[MAXN]; void MultiPle(long long *aa, long long *bb, long long *cc, int len){ for(int i=0; i<len; ++i){ tmp[i] = 0; for(int j=0; j<len; ++j){ if(i - j >= 0){ tmp[i] += (aa[j] * bb[i - j]) % m; }else{ tmp[i] += (aa[j] * bb[i - j + n]) % m; } tmp[i] %= m; } } for(int i=0; i<len; ++i){ cc[i] = tmp[i]; } } int main(){ freopen("in.txt", "r", stdin); while(scanf("%lld %lld %lld %lld", &n, &m, &d, &k) != EOF){ for(int i=0; i<n; ++i){ scanf("%lld", &num[i]); } memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b)); for(int i=0; i<=d; ++i){ a[i] = 1; } for(int i=n-1; i>n-1-d; --i){ a[i] = 1; } b[0] = 1; while(k){ if(k % 2 == 1){ MultiPle(b, a, b, n); } k /= 2; MultiPle(a, a, a, n); } MultiPle(num, b, ans, n ); for(int i=0; i<n-1; ++i){ printf("%lld ", ans[i]); } printf("%lld\n", ans[n-1] ); } return 0; }