bzoj4600 [Sdoi2016]コインゲームsg関数+結論

sg [maxQ] [2回の回数] [3回の回数] =前のものはすべて正の勝ち負けです

Cは異なり、互いに独立しています

まず、彼は模倣関係にあるので、順序は重要ではありません。

たとえば、9、3は0であり、勝利戦略は9を選択して9、3を回すことです。

  排他的論理和であるため、勝ち戦略は9を選択して9を回すと理解できます。したがって、3の位置を2回回す必要があります。これは、0回回すのと同じです。

3の位置はすでに0であることが理解できます(実際の操作は模倣と同等です)

したがって、勝利戦略がある場合は、各ポイントのsg値のいくつかの組み合わせに分割する必要があります。0ポイントを選択して、前の0ポイントを1に変更します

これは、前の0点を独立した点の角度に保つこととして理解でき、残りは排他的であるか、前の0点のsgで0に等しくなります。

なぜなら、最初の手が0の場合、秒の手は1でなければならず、最初の手は1であり、秒の手は0でなければなりません。これは、曲がることができないことと同じです。

XORの性質からも理解できます。

コード:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int sg[23][55][55],n,T,i,j,Q,ans,o,er[30005],san[30005];
int SG(int Q,int a,int b)
{
	if(sg[Q][a][b]!=-1)return sg[Q][a][b];
int i,j,q,p;
bool v[101];
memset(v,0,sizeof(v));
for(p=1;p<=a;p++)
{int lin=0;
for(q=1;q<=Q;q++)
{
if(p*q>a)break;	
	lin^=SG(Q,a-p*q,b);
	v[lin]=1;
}
}
for(p=1;p<=b;p++)	
{int lin=0;
for(q=1;q<=Q;q++)
{
if(p*q>b)break;	
	lin^=SG(Q,a,b-p*q);
	v[lin]=1;
}
}
	for(i=0;i<=100;i++)
	{
		if(v[i]==0)
		{sg[Q][a][b]=i;break;}
	}
	return sg[Q][a][b];
}
int main()
{
	scanf("%d",&T);
	memset(sg,-1,sizeof(sg));
	for(Q=1;Q<=20;Q++)
	for(i=0;i<=15;i++)
	for(j=0;j<=15;j++)
	{
		SG(Q,i,j);
	}
	int linn=0;
	for(i=1;i<=30000;i++)
	{
		o=i;
			int o2=0;
			int o3=0;
			while(o%2==0)
			o/=2,o2++;
			while(o%3==0)
			o/=3,o3++;
			er[i]=o2;san[i]=o3;
		linn=max(linn,max(o2,o3));
	}
	while(T--)
	{ans=0;
		scanf("%d%d",&n,&Q);
		for(i=1;i<=n;i++)
		{
			scanf("%d",&o);
			if(o==1)continue;
			ans^=sg[Q][er[i]][san[i]];
		}
		if(ans==0)printf("lose\n");
		else printf("win\n");
	}
 } 

  


おすすめ

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