bzoj2066: [Poi2004]Gra

传送门:http://www.lydsy.com:808/JudgeOnline/problem.php?id=2066

思路:首先谁移到m-1谁就输了,这是多么显然啊....

其实这个可以转化为上一篇中的阶梯NIM。

连续的一堆就是一个阶梯上的石子,两个连续的一堆间隔的空阶梯数是空格数-1(这点一定要注意)

然后考虑对于连续的一堆棋子,如果我们从中间移走一个,使之变为数量为x和y的两段,那么就等价于从一个阶梯向下一个阶梯移动了y个石子。


对于方案数,只要枚举+判断就可以了

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
const int maxn=1000010;
using namespace std;
int n,m,a[maxn],cnt,b[maxn],ans,tot;char ch;

void read(int &x){
	for (ch=getchar();!isdigit(ch);ch=getchar());
	for (x=0;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
}

int main(){
	scanf("%d%d",&m,&n);
	for (int i=1;i<=n;i++) read(a[i]);
	if (a[n]==m-1){
		ans=1;
		for (int i=n;i&&a[i]-a[i-1]==1;i--,ans++);
		return printf("%d\n",ans),0;
	}
	a[n+1]=m-1;
	for (int i=n;i;i--)
		if (a[i+1]-a[i]==1) b[cnt]++;
		else if (a[i+1]-a[i]==2){
			if (cnt&1) ans=ans^b[cnt];
			b[++cnt]=1;
		}
		else{
			if (cnt&1) ans=ans^b[cnt];
			cnt+=3-((a[i+1]-a[i])&1),b[cnt]=1;
		}
	if (cnt&1) ans=ans^b[cnt];
	if (ans)
		for (int i=1;i<=cnt;i++)
			if ((i&1)&&(ans^b[i])<b[i]||i%2==0&&(ans^b[i-1])>b[i-1]&&(ans^b[i-1])<=b[i-1]+b[i])
				tot++;
	printf("%d\n",tot);
	return 0;
}


你可能感兴趣的:(博弈组合游戏)