【BZOJ4417】: [Shoi2013]超级跳马
题目链接:
题解:
矩阵快速幂优化DP。
先考虑$nm^2$DP,设$f_{(i,j)}$表示从$1,1$到$i,j$的方案,显然这个方程和奇偶性有关,我们考虑某列的$i$同奇偶性的转移和奇偶性相异的贡献,很容易把刚才的方程变成$nm$的轮换式方程,即$f_{(0/1,j)}$表示偶/奇数列第$j$行的方案数。此时转移方程为$$f_{(i,j)}=f_{(i,j)}+\sum_{x=-1}^{1}f_{(i(xor)1,j+x)}$$
然后考虑如何用矩阵优化,画图发现十字相乘时,如果我们把奇偶分成两列会没办法转移,然后考虑十字相乘性质,我们可以把奇偶两列转换为一列上的两段,这样我们构建$(2n)^2$的矩阵,至于递推矩阵,YY一下即可。
代码:
#define Troy 10/24/2017 #include <bits/stdc++.h> using namespace std; inline int read(){ int s=0,k=1;char ch=getchar(); while(ch<'0'|ch>'9') ch=='-'?k=-1:0,ch=getchar(); while(ch>47&ch<='9') s=s*10+(ch^48),ch=getchar(); return s*k; } const int mod=30011; int n,m; struct Matrix{ int a[101][101]; Matrix(){memset(a,0,sizeof(a));} inline void e1(){ for(int i=1;i<=2*n;i++) a[i][i]=1; } inline friend Matrix operator *(Matrix x,Matrix y){ Matrix z; for(int i=1;i<=2*n;i++) for(int j=1;j<=2*n;j++) for(int k=1;k<=2*n;k++) z.a[i][j]=(z.a[i][j]+x.a[i][k]*1ll*y.a[k][j])%mod; return z; } inline friend Matrix operator ^(Matrix a,long long b){ Matrix ret;ret.e1(); while(b){ if(b&1) ret=ret*a; a=a*a;b>>=1; }return ret; } }; int main(){ n=read(),m=read(); if(m==1){ puts(n==1?"1":"0"); return 0; } Matrix ans; ans.a[1+n][1]=1; if(n>1) ans.a[2+n][1]=1; Matrix t; for(int i=1;i<=n;i++){ t.a[i][i+n]=1; t.a[i+n][i]=1; t.a[i+n][i+n]=1; if(i-1) t.a[i+n][i+n-1]=1; if(i+1<=n) t.a[i+n][i+n+1]=1; } ans=(t^(m-2))*ans; printf("%d",ans.a[2*n][1]); }
没有什么不可能。