取石子游戏’s 题解

是一道水题

题面:小H和小Z正在玩一个取石子游戏。 取石子游戏的规则是这样的,每个人每次可以从一堆石子中取出若干个石子,每次取石子的个数有限制,谁不能取石子时就会输掉游戏。 小H先进行操作,他想问你他是否有必胜策略,如果有,第一步如何取石子。
一句话题解:暴力求出sg函数,再暴力枚举第一步看是否转移成了必败状态输出即可(因为转移到必败即是让先手必胜的走法)。
好的结束了。
咳,代码稍加收拾一下吧。

#include 
using namespace std;
const int N=10+1,A=1e3+5;
int n,m,a[N],b[N],sg[A],v[N],ans=0;
void init(){
	scanf("%d",&n);
	for(int i=0;++i<=n;scanf("%d",&a[i]));
	scanf("%d",&m);
	for(int i=0;++i<=m;scanf("%d",&b[i]));
}
void work(){
	for(int i=0;++i<A;){
		memset(v,0,sizeof(v));
		for(int j=0;++j<=m;i-b[j]<0?:v[sg[i-b[j]]]=1);
		//看要转移到的i-b[j]的状态是否成立,并标记sg[i-b[j]]待转移
		for(int j=-1;++j<N;) if(!v[j]){
			sg[i]=j;//sg函数表示的是最小的不能转移到的状态
			break ;
		}
	}
	for(int i=0;++i<=n;ans^=sg[a[i]]);
}
void prin(){
	if(ans){
		printf("YES\n");
		for(int i=0;++i<=n;) for(int j=0;++j<=m;) if(sg[a[i]-b[j]]==(ans^sg[a[i]])){
		//if语句即是判断能否转移到必败状态(当前堆转以后的sg=另外所有堆的sg和)
			printf("%d %d",i,b[j]);
			return ;
		}
	}
	else printf("NO");
}
int main(){
	init();
	work();
	prin();
	return 0;
} 

代码真丑

你可能感兴趣的:(题解)