poj 3150 Cellular Automaton 矩阵快速幂

题目链接:

http://poj.org/problem?id=3150

题意:

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

思路:

http://blog.csdn.net/lin375691011/article/details/38493267

矩阵快速幂加速递推。

按照正常思路第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]

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

代码:

 1 #include <iostream>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <cstdio>
 5 using namespace std;
 6 typedef long long ll;
 7 #define MS(a) memset(a,0,sizeof(a))
 8 #define MP make_pair
 9 #define PB push_back
10 const int INF = 0x3f3f3f3f;
11 const ll INFLL = 0x3f3f3f3f3f3f3f3fLL;
12 inline ll read(){
13     ll x=0,f=1;char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
16     return x*f;
17 }
18 //////////////////////////////////////////////////////////////////////////
19 const int maxn = 1e5+10;
20 
21 struct matrix{
22     ll m[505];
23     void clear(){
24         MS(m);
25     }
26 }r,a,ans;
27 
28 int n,mod,d,k;
29 
30 matrix mul(matrix a,matrix b){
31     matrix re;
32     re.clear();
33     int p;
34     for(int i=0; i<n; i++){
35         p = (n-i)%n;
36         for(int j=0; j<n; j++){
37             re.m[i] = (re.m[i]+a.m[j]*b.m[p])%mod;
38             p = (p+1)%n;
39         }
40     }
41     return re;
42 }
43 
44 matrix qpow(int k){
45     matrix e;
46     e.clear();
47     e.m[0] = 1;
48     while(k){
49         if(k & 1) e = mul(e,a);
50         a = mul(a,a);
51         k >>= 1;
52     }
53     return e;
54 }
55 
56 int main(){
57     while(cin>>n>>mod>>d>>k){
58         a.clear(); r.clear();
59         for(int i=0; i<n; i++){
60             r.m[i] = read();
61         }
62 
63         for(int i=0; i<n; i++){
64             if(i<=d || (n-i)<=d) a.m[i] = 1;
65             else a.m[i] = 0;
66         }
67 
68         a = qpow(k);
69 
70         ans = mul(r,a);
71 
72         for(int i=0; i<n; i++){
73             if(i) printf(" ");
74             cout << ans.m[i];
75         }
76         puts("");
77     }
78 
79     return 0;
80 }
原文地址:https://www.cnblogs.com/yxg123123/p/6837633.html