设f[i][j]表示方案数,显然有一个O(m2n)的暴力DP法,但实际上可以按距离当前位置的奇偶性分成s1[i][j]和s2[i][j],然后这个暴力DP可以优化到O(nm)的暴力。于是有这样的递推式:s1[i+1][j]=s2[i][j]+s1[i][j−1]+s1[i][j]+s1[i][j+1],s2[i+1][j]=s1[i][j],这个显然能够矩乘的,然后就直接转移即可,答案就是s1[m][n]−s2[m−1][n]。


#include<bits/stdc++.h> using namespace std; const int mod=30011; int n,m; struct mat{ int a[105][105]; mat(){memset(a,0,sizeof a);} }A,B,S; mat operator*(mat a,mat b) { mat c; for(int i=1;i<=2*n;i++) for(int j=1;j<=2*n;j++) for(int k=1;k<=2*n;k++) c.a[i][j]=(c.a[i][j]+a.a[i][k]*b.a[k][j])%mod; return c; } mat qpow(mat a,int b) { mat ret;for(int i=1;i<=2*n;i++)ret.a[i][i]=1; while(b) { if(b&1)ret=ret*a; a=a*a,b>>=1; } return ret; } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=n;i++)S.a[i][i]=S.a[i+n][i]=S.a[i][i+n]=1; for(int i=1;i<n;i++)S.a[i+1][i]=S.a[i][i+1]=1; A=qpow(S,m-2),B=A*S; printf("%d",(B.a[1][n]-A.a[1][n<<1]+mod)%mod); }