在比赛时一直弄不出这道题,虽知是博弈要用到异或运算,但在找连续的一串数时没什么好的想法,于是就悲剧了……赛后,在广大last大牛的指点下终于把它给过了,总的来说还是太水了……
思路:先设sum=(n+1)*n/2,从左到右求出1到i的nim(即1-i异或得到的数),然后把nim[i]从小到大排序,接下来就找到每一段相同的nim数的长度len,用sum-=len*(len-1)/2,当,nim[i]==0时sum要多减去其长度len,即sum-=len。其证明就不详细地说了,想想应该明白的。还有几个地方要注意的就是n,sum,len要用long long啊,在这里wa了几次,坑爹啊!
#include<cstring>
#include<cstdio>
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
#define FRE freopen("a.txt","r",stdin);
#define LL long long
#define N 100005
int main()
{
//FRE;
int t;
scanf("%d",&t);
while(t--)
{
LL n;
int s,w;
scanf("%lld%d%d",&n,&s,&w);
int g=s;
int a[N];
for(int i=1;i<=n;i++)
{
a[i]=g;
if(a[i]==0)a[i]=g=w;
if(g%2)g=(g/2)^w;
else g/=2;
}
int nim[N];
nim[0]=0;
for(int i=1;i<=n;i++)nim[i]=a[i]^nim[i-1];
sort(nim+1,nim+n+1);
LL sum=(n+1)*n/2,len=0;
int pre;
bool flag=true;
for(int i=1;i<=n;i++)
{
if(flag)
{
pre=nim[i];
flag=false;
}
if(nim[i]==pre)len++;
else
{
sum-=len*(len-1)/2;
if(pre==0)sum-=len;
pre=nim[i];
len=1;
}
}
sum-=len*(len-1)/2;
printf("%lld\n",sum);
}
return 0;
}