bzoj4417 [Shoi2013]スーパーボールティングマトリックス

手で遊んでいると、転送の法則を調べたところ、パリティで分類できることがわかりました。パリティの異なるポイントは隣接する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);
}


おすすめ

転載: blog.csdn.net/haobang866/article/details/79248282