矩阵快速幂基础
这里放一下矩阵快速幂的模板.
首先我们怎样记得转移矩阵的行列数呢,我么用手比划一下,先横,再竖着.为答案矩阵的一个元素,
所以第一个矩阵的列数与转移矩阵的横数相等,转移矩阵的列数与答案矩阵的列数相等...
#include<bits/stdc++.h> #define db double #define ll long long #define reg register #define pb(x) push_back(x) #define fup(i,x,y) for(reg int i=x;i<=y;++i) #define fdw(i,x,y) for(reg int i=x;i>=y;--i) using namespace std; const int mod=10000; int n; struct wy { ll a[5][5]; wy(){memset(a,0,sizeof(a));} inline void clear () { memset(a,0,sizeof(a)); } wy friend operator *(wy a,wy b) { wy c; fup(i,1,2) fup(j,1,2) fup(k,1,2) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } wy friend operator ^(wy a,ll y) { wy c; fup(i,1,2) c.a[i][i]=1; while(y) { if(y&1) c=c*a; y>>=1; a=a*a; } return c; } }A,B,C; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } int main() { freopen("1.in","r",stdin); B.a[1][1]=0;B.a[1][2]=1; B.a[2][1]=1;B.a[2][2]=1; while(1) { n=read(); if(n==-1) break; if(n<=2) { if(n==0) puts("0"); else puts("1"); continue; } A.clear(); A.a[1][1]=1;A.a[1][2]=1; C=B^(n-2); A=A*C; printf("%lld\n",A.a[1][2]); } return 0; }
注意判断边界..
#include<bits/stdc++.h> #define db double #define ll long long #define reg register #define pb(x) push_back(x) #define fup(i,x,y) for(reg int i=x;i<=y;++i) #define fdw(i,x,y) for(reg int i=x;i>=y;--i) using namespace std; int l=64,n,m,t,act; int d[10][10],len[20]; char st[20][10]; struct wy { ll a[70][70]; wy(){memset(a,0,sizeof(a));} inline void dan() { memset(a,0,sizeof(a)); fup(i,0,l) a[i][i]=1; } wy friend operator *(wy a,wy b) { wy c; fup(i,0,l) fup(j,0,l) fup(k,0,l) c.a[i][j]=c.a[i][j]+a.a[i][k]*b.a[k][j]; return c; } wy friend operator ^(wy a,ll y) { wy c; fup(i,0,l) c.a[i][i]=1; while(y) { if(y&1) c=c*a; y>>=1; a=a*a; } return c; } }A[70],B,C; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } int main() { n=read();m=read();t=read();act=read(); fup(i,1,n) fup(j,1,m) { char c;cin>>c; d[i][j]=c-'0'; } fup(i,0,act-1) scanf("%s",st[i]+1),len[i]=strlen(st[i]+1); fup(k,1,60) { A[k].a[0][0]=1; fup(i,1,n) fup(j,1,m) { int id=(i-1)*m+j; int op=k%len[d[i][j]]?(k%len[d[i][j]]):(len[d[i][j]]); if(st[d[i][j]][op]>='0'&&st[d[i][j]][op]<='9') { A[k].a[0][id]=st[d[i][j]][op]-'0'; A[k].a[id][id]=1; } else if(st[d[i][j]][op]=='D') continue; else { if(st[d[i][j]][op]=='N'&&i!=1) A[k].a[id][(i-2)*m+j]=1; else if(st[d[i][j]][op]=='W'&&j!=1) A[k].a[id][id-1]=1; else if(st[d[i][j]][op]=='S'&&i!=n) A[k].a[id][i*m+j]=1; else if(st[d[i][j]][op]=='E'&&j!=m) A[k].a[id][id+1]=1; } } } C.dan(); fup(i,1,60) C=C*A[i]; C=C^(t/60); B.a[1][0]=1; B=B*C; fup(i,1,t%60) { B=B*A[i]; } ll ans=0; fup(i,1,n*m) ans=max(ans,B.a[1][i]); printf("%lld",ans); return 0; }
[TJOI2017]可乐
//又是一眼看过去就没有思路的题... //算了,还是慢慢来吧,一点一点看这道题.. //首先看到这道题的第一印象,dp嗯.. //可后来发现由于好像有环...好像不怎么行,但还是得抱着人有多大胆,地有多大产的思想试试. //我们设f[i][j]表示前j秒到达i的方案数...f[i][j]+=f[k][j-1]..(k->i). //但好像有环,且原地不动和自爆怎么搞...不行,看来dp不能用这种形式瞎搞,思考这道题的本质. //题目给定无向图,求在t内的所有方案数.... //由于最开始处于1号点,实际上就是求1号点在t时间内到其他点的方案数. //我们思考如何求到其他点的方案数...我们发现由于环的缘故我们不能简单的用上一个dp类似的状态求解. //这要求我们增加状态,设f[i][j]表示i到j的方案数.显然f[i][j]=f[i][k]*f[k][j]. //(这样思考,我们由于无法确定从哪过来的所以这样记录下来.表示前t秒从i到j的方案数.所以不用管t秒是如何分配的) //之后思考原地不动和爆炸如何搞定.原地不动就是待在原地,那连个自环即可.爆炸就是我们新建一个虚拟节点,只从各个节点 //向它连边即可,这样就能达到爆炸就无法复原的效果了. //之后由于时间的限制,我们无法快速求解上面的dp,但却能惊奇的发现,好像矩阵乘法啊..... //于是就愉快地写题了. #include<bits/stdc++.h> #define db double #define ll long long #define reg register #define pb(x) push_back(x) #define fup(i,x,y) for(reg int i=x;i<=y;++i) #define fdw(i,x,y) for(reg int i=x;i>=y;--i) using namespace std; const int N=110,mod=2017; int n,m,t; struct wy { int a[N][N]; wy(){memset(a,0,sizeof(a));} wy friend operator *(wy a,wy b) { wy c; fup(i,0,n) fup(j,0,n) fup(k,0,n) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } wy friend operator ^(wy a,int y) { wy c; fup(i,0,n) c.a[i][i]=1; while(y) { if(y&1) c=c*a; y>>=1; a=a*a; } return c; } }C; inline int read() { int x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } int main() { freopen("1.in","r",stdin); n=read();m=read(); fup(i,1,m) { int x=read(),y=read(); C.a[x][y]=1;C.a[y][x]=1; } t=read(); fup(i,0,n) C.a[i][0]=1,C.a[i][i]=1; C=C^t; int ans=0; fup(i,0,n) ans=(ans+C.a[1][i])%mod; printf("%d",ans); return 0; }
P5175 数列
#include<bits/stdc++.h> #define db double #define ll long long #define reg register #define pb(x) push_back(x) #define rep(i,x,y) for(reg int i=x;i<=y;++i) #define fdw(i,x,y) for(reg int i=x;i>=y;--i) using namespace std; const int mod=1e9+7; ll T,n,a1,a2,x,y; struct wy { ll a[5][5]; wy() {memset(a,0,sizeof(a));} inline void clear() {memset(a,0,sizeof(a));} wy friend operator *(wy a,wy b) { wy c; rep(i,1,4) rep(j,1,4) rep(k,1,4) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } wy friend operator ^(wy a,ll y) { wy c; rep(i,1,4) c.a[i][i]=1; while(y) { if(y&1) c=c*a; y>>=1; a=a*a; } return c; } }A,B; inline ll read() { ll x=0,ff=1; char ch=getchar(); while(!isdigit(ch)) {if(ch=='-') ff=-1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} return x*ff; } int main() { //freopen("1.in","r",stdin); T=read(); while(T--) { n=read();a1=read();a2=read();x=read();y=read(); if(n==1) printf("%lld\n",a1*a1%mod); else if(n==2) printf("%lld\n",(a1*a1%mod+a2*a2%mod)%mod); else { A.clear();B.clear(); A.a[1][1]=a1*a1%mod;A.a[1][2]=a2*a2%mod;A.a[1][3]=a1*a2%mod;A.a[1][4]=(a1*a1%mod+a2*a2%mod)%mod; B.a[1][1]=0;B.a[1][2]=y*y%mod;B.a[1][3]=0;B.a[1][4]=y*y%mod; B.a[2][1]=1;B.a[2][2]=x*x%mod;B.a[2][3]=x;B.a[2][4]=x*x%mod; B.a[3][1]=0;B.a[3][2]=2*x*y%mod;B.a[3][3]=y;B.a[3][4]=2*x*y%mod; B.a[4][1]=0;B.a[4][2]=0;B.a[4][3]=0;B.a[4][4]=1; B=B^(n-2); A=A*B; printf("%lld\n",A.a[1][4]); } } return 0; }