传送门: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;
}