手で遊んでいると、転送の法則を調べたところ、パリティで分類できることがわかりました。パリティの異なるポイントは隣接する3列に転送でき、同じパリティのポイントは転送できません。
したがって、各行について、奇数と偶数のプレフィックスの合計を記録して、同じ行をスキャンするポイントを節約できるようにします。
ペアワイズ転送であるため、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);
}