在手玩的时候找转移的规律,发现可以奇偶分类,不同奇偶的点相邻3行全都可以+1转移,同奇偶的点不可以转移
所以对于每一行,都记录奇偶两种的前缀和,就可以省去扫同行的点
注意,由于是两两转移,要注意区分12->34 中的1->4和 1->2,为了避免3->4就需要独立的12->3 12->4
可以以3为桥梁 12->3->4,注意写清楚不要乱
注意特判n=1
码:
#include<iostream>
#include<cstdio>
using namespace std;
#define HA 30011
int n,m,i,j,k,f[150][150],b[150],c[150][150],a[150],g[150][150];
int main()
{
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
{
f[i][i]=1;
}
for(i=1+n;i<=2*n;i++)
{
if(i-n-1>=1)f[i][i-n-1]=1;
if(i-n+1<=n)f[i][i-n+1]=1;
f[i][i-n]=1;
}//下一个左边的转移
for(i=1+n;i<=n*2;i++)
{
f[i][i]=1;
}
for(i=1;i<=2*n;i++)
for(j=1;j<=n;j++)
{
if(j>1)f[i][j+n-1]+=f[i][j];
if(j<n)f[i][j+n+1]+=f[i][j];
f[i][j+n]+=f[i][j];
}
//下一个右边的转移
a[1]=1;
a[1+n]=a[2+n]=1;
int lin=m/2;
lin--;
while(lin)
{
if(lin&1)//答案转移上
{
for(i=1;i<=n*2;i++)
for(j=1;j<=n*2;j++)//n*2 to n*2
{
b[j]+=a[i]*f[i][j];
b[j]%=HA;
}
for(i=1;i<=2*n;i++)a[i]=b[i],b[i]=0;
}
lin/=2;
for(i=1;i<=n*2;i++)
for(j=1;j<=n*2;j++)
for(k=1;k<=n*2;k++)
{
c[i][k]+=f[i][j]*f[j][k];
c[i][k]%=HA;
}
for(i=1;i<=2*n;i++)
for(j=1;j<=2*n;j++)
f[i][j]=c[i][j],c[i][j]=0;
}
if(m&1)
printf("%d",(a[2*n]+(n==1?0:a[2*n-1]))%HA);
else printf("%d",(a[n]+(n==1?0:a[n-1]))%HA);
}