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; }