poj3150 Cellular Automaton(矩阵快速幂)
2016-07-25 18:38
281 查看
对于样例:
5311
12212
使得
a = {1 2 2 1 2};
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
}
变换一次,矩阵相乘 a * b = 5 5 5 5 4;各项对取余就是结果;
如果变换k次,结果就是a×(b^k);所以用矩阵快速幂计算b^n;
但是n×n的矩阵会超时啊,而且要long long[500+][500+],数组太大,连本地都开不开。
但是矩阵b比较对称,可以发现
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]
第i行是第i-1行向右平移一位。所以计算和存储都只关于第一行就行了。
数据较大,取余太多,用时就比较多,尽量少取余。
5311
12212
使得
a = {1 2 2 1 2};
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
}
变换一次,矩阵相乘 a * b = 5 5 5 5 4;各项对取余就是结果;
如果变换k次,结果就是a×(b^k);所以用矩阵快速幂计算b^n;
但是n×n的矩阵会超时啊,而且要long long[500+][500+],数组太大,连本地都开不开。
但是矩阵b比较对称,可以发现
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]
第i行是第i-1行向右平移一位。所以计算和存储都只关于第一行就行了。
数据较大,取余太多,用时就比较多,尽量少取余。
#include<iostream> #include<cstdio> #include<cstring> #include<string> #include<cmath> #include<algorithm> #include<queue> #include<vector> #define LL long long #define maxn 550 using namespace std; int MOD,N; struct Mat{ LL at[maxn]; int n; Mat(){n=N;} }; Mat mul(const Mat &a,const Mat &b) { Mat t; memset(t.at,0,sizeof(t.at)); int p=0; for(int i=0;i<a.n;++i) { for(int j=0;j<a.n;++j) { if(p==a.n)p=0; t.at[i]+=(a.at[j]*b.at[p++]); } p--; t.at[i]%=MOD; } return t; } Mat _pow (Mat p,int k) { if(k==1)return p; Mat e; memset(e.at,0,sizeof(e.at)); e.at[0]=1; if(k==0)return e; while(k) { if(k&1)e=mul(e,p); p=mul(p,p); k>>=1; } return e; } int main() { LL arr[maxn]; int n,d,k; while(~scanf("%d%d%d%d",&N,&MOD,&d,&k)) { n=N; Mat tmp; memset(tmp.at,0,sizeof(tmp.at)); tmp.at[0]=1; for(int i=1;i<=d;++i) { tmp.at[i]=1; int pos=-i; if(pos<0)pos+=n; tmp.at[pos]=1; } tmp=_pow(tmp,k); for(int i=0;i<n;++i) { scanf("%lld",&arr[i]); } int p=0; for(int i=0;i<n;++i) { LL ans=0; for(int j=0;j<n;++j) { if(p==n)p=0; ans+=arr[j]*tmp.at[p++]; } p--; ans%=MOD; if(i!=0) printf(" "); printf("%lld",ans); } printf("\n"); } }
相关文章推荐
- 初学ACM - 组合数学基础题目PKU 1833
- POJ ACM 1001
- POJ ACM 1002
- 1611:The Suspects
- POJ1089 区间合并
- POJ 2159 Ancient Cipher
- POJ 2635 The Embarrassed Cryptographe
- POJ 3292 Semi-prime H-numbers
- POJ 2773 HAPPY 2006
- POJ 3090 Visible Lattice Points
- POJ-2409-Let it Bead&&NYOJ-280-LK的项链
- POJ-1695-Magazine Delivery-dp
- POJ1523 SPF dfs
- POJ-1001 求高精度幂-大数乘法系列
- POJ-1003 Hangover
- POJ-1004 Financial Management
- [数论]poj2635__The Embarrassed Cryptographer
- [二分图匹配]poj2446__Chessboard
- POJ1050 最大子矩阵和
- 用单调栈解决最大连续矩形面积问题