一道不算太裸的矩阵乘法。
考虑对奇数和偶数分开来计算,令dp1[i][j]表示到第2i-1列在第j行的方案,dp2[i][j]表示到第2i列第j行的方案,那么显然有dp1[i][j]=Σdp2[1..i-1][j],dp2类似。考虑做一个令f[i][j]为dp[1..i][j]的前缀和,那么就有f1[i][j]=f1[i-1][j]+f2[i][j],f2[i][j]=f2[i-1][j]+f1[i][j]。
那么对后面那个就是一个简单的递推式了,可以用矩阵乘法加速。由于有两个数组,我们把它们合成一个用i表示f1中的i,i+1表示f2中的i,然后就可以两行两行计算了。注意对m的奇偶性进行判断,因为初值是不同的。
AC代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#define p 30011
using namespace std;
int n,m,cnt; struct matrix{ int t[105][105]; }a,b,c;
matrix tms(matrix x,matrix y){
matrix z; int i,j,k;
for (i=1; i<=cnt; i++)
for (j=1; j<=cnt; j++){
z.t[i][j]=0;
for (k=1; k<=cnt; k++) z.t[i][j]=(z.t[i][j]+x.t[i][k]*y.t[k][j])%p;
}
return z;
}
int main(){
scanf("%d%d",&n,&m); cnt=n<<1; int i,k;
m--; if (m==1){ puts((n<3)?"1":"0"); return 0; }
for (i=1; i<=n; i++){
a.t[i][i]=a.t[i+n][i+n]=b.t[i][i]=b.t[i+n][i+n]=1;
for (k=i-1; k<=i+1; k++)
if (k>0 && k<=n) a.t[i][k+n]=b.t[i+n][k]=1;
}
c.t[1][1]=1; if (m&1){ c.t[1][2]=c.t[1][n+1]=1; }
m>>=1; a=tms(a,b); memcpy(b.t,a.t,sizeof(a.t));
for (i=m-1; i; i>>=1,a=tms(a,a)) if (i&1) c=tms(c,a);
printf("%d\n",(tms(c,b).t[1][n]-c.t[1][n]+p)%p);
return 0;
}
by lych
2016.3.9