矩阵快速幂优化dp……大概似乎还是很裸的……然而我昨天才学会这套理论于是考试只好在200+分场里110滚粗【哭
嗯考虑用f[i][j]表示在第i行第j列的方案总数
转移的话,因为只能跳奇数格,所以f[i][j]=f[i-2][j]+f[i-1][j-1]+f[i-1][j]+f[i-1][j+1](边界啥的判一下就是了
如果不考虑从i-1列转移的方案,那么f[i][j]==f[i-2][j],于是再加上相邻的那三个格子的贡献就好了……
发现第二维足够小,而且只和前两列的结果有关,所以直接用矩阵搞一搞就好
用一个2n*1的矩阵来记录答案,上面n行记录f[i-1],下面n行记录f[i-2],转移的时候把上面一半粘到下面来,f[i]就按照递推式更新就好
当n==3时,转移矩阵差不多是这样的↓(这四块的位置应该随便吧……反正差不多就好23333
1 1 0 1 0 0
1 1 1 0 1 0
0 1 1 0 0 1
1 0 0 0 0 0
0 1 0 0 0 0
0 0 1 0 0 0
#include<bits/stdc++.h>
#define MAXN 105
#define MAXM 1000000057
#define MOD 30011
using namespace std; int n,m;
struct matrix{
int d[MAXN][MAXN];
int x,y;
matrix(){x=y=0,memset(d,0,sizeof d);}
matrix(int xx):x(xx),y(xx){
memset(d,0,sizeof d);
for(int i=0;i<x;++i)
d[i][i]=1;
}
matrix(int xx,int yy):x(xx),y(yy){memset(d,0,sizeof d);}
matrix operator * (const matrix ano) {
matrix TMP(x,ano.y);
for(int i=0;i<x;++i)
for(int j=0;j<y;++j)
for(int k=0;k<ano.y;++k)
TMP.d[i][k]+=d[i][j]*ano.d[j][k],TMP.d[i][k]%=MOD;
// TMP.write();
return TMP;
}
matrix pow(long long cf){
matrix RTN(x),TMP=*this;
for(;cf;cf>>=1,TMP=TMP*TMP)
if(cf&1)
RTN=RTN*TMP;
return RTN;
}
void write(){
for(int i=0;i<x;++i){
for(int j=0;j<y;++j) printf("%d ",d[i][j]);
puts("");
}
puts("");
}
}A,B,P,F;
int main(){
scanf("%d%d",&n,&m);
if(n>m) return puts("0"),0;
----m;
A=B=matrix(n<<1,n<<1);
P=matrix(n<<1,1);
P.d[0][0]=P.d[1][0]=1;
if(n==1&&m>=2) P.d[1][0]=0;
// P.write();
for(int i=0;i<n;++i){
A.d[i][i+n]=A.d[i+n][i]=1;
for(int j=max(i-1,0);j<=min(i+1,n-1);++j) A.d[i][j]=1;
}
B=A.pow(m);
P=B*P;
// for(int i=1;i<=m;++i) P=A*P;
printf("%d",P.d[n-1][0]);
return 0;
}