题目的意思是给你n个ai,有多少种不同的连续段使得用该段数中所有的数字玩Nim游戏的先手必胜。
首先根据博弈论的知识,我们知道,要使先手必胜,那么只要保证所有的数的异或值不为0就可以了。
这个题目,给的ai的求法给了我很大的误导,我一开始以为要从哪里入手来突破这个题目。结果。。。。。。。深坑啊。
是这样来考虑的,我们直接模拟,分别得出所有的ai的值,然后用一个数字fi表示a1到ai连续的数的异或值。
这样要求异或不为0的情况,我们只要求出所有值为0的情况,然后将所有的情况减去这些情况就可以了。
对于求所有值为0的情况,有两种可能:
一、f[i]=0,说明从1到i的数所有的数的异或值就为0,这就是一个满足条件的段哦。
二、存在1<=i<j<=n,f[i]=f[j],这说明i+1到j这一段的所有的异或值为0(异或的性质哦),这也是一个满足条件的段。
有了上面的两点,我们就可以进行统计了。
统计有两种方法:
一、排个序,然后对于值相同的两两组合就好了。
二、用map哈希的方法记录每一个数出现了多少种情况,然后组合一下就好了。
1 #include <iostream> 2 #include <cstdio> 3 #include <map> 4 #include <algorithm> 5 #include <cstring> 6 #define ll long long 7 #define maxn 100100 8 using namespace std; 9 10 int n,m,k,a[maxn],S,W,t; 11 ll ans,tot; 12 13 int main() 14 { 15 cin>>t; 16 while (t--) 17 { 18 scanf("%d%d%d",&n,&S,&W); 19 ans=(ll)n*(n+1)/2,tot=0; 20 int g = S; 21 for (int i=1; i<=n; i++) 22 { 23 a[i] = g; 24 if( a[i] == 0 ) { a[i] = g = W; } 25 if( g%2 == 0 ) { g = (g/2); } 26 else { g = (g/2) ^ W; } 27 } 28 k=0; 29 for (int i=1; i<=n; i++) 30 { 31 k^=a[i]; 32 a[i]=k; 33 } 34 sort(a+1,a+1+n); 35 k=1,a[n+1]=a[0]=-1; 36 for (int i=2; i<=n+1; i++) 37 { 38 if (a[i]==a[i-1]) k++; 39 else 40 { 41 if (a[i-1]==0) tot+=k; 42 tot+=(ll)k*(k-1)/2; 43 k=1; 44 } 45 } 46 printf("%lld ",ans-tot); 47 } 48 return 0; 49 }