http://codeforces.com/contest/1054/problem/D
题目大意:一个序列a1 a2...an,可以对若干个元素进行取反,使所得的新序列异或和为0的区间个数最多.
题目分析:首先易知每个位置的前缀异或和的值只有两种,因为对元素进行取反时,取偶数个元素异或和不变,奇数个元素就是原值取反.然后由于对一个位置取反,不会影响后面位置与这个位置的前缀异或和相同的位置个数(因为这个位置取反后,后面各个位置的前缀异或和也跟着改变),所以一个位置的改变只会影响与前面位置前缀和相同的个数,所以只需要贪心地根据前面位置值出现次数来进行是否取反该位置的判断.
1 #include<iostream> 2 #include<cstring> 3 #include<cmath> 4 #include<map> 5 #include<cstdio> 6 using namespace std; 7 typedef long long ll; 8 ll q[200005]; 9 map<int ,int>nums; 10 int main(){ 11 ll n,k; 12 cin>>n>>k; 13 for(int i=0;i<n;i++){ 14 scanf("%lld",&q[i]); 15 } 16 ll s=(1<<k)-1; 17 ll res=q[0]; 18 ll ans=(n+1)*n/2; 19 if(res==0){ 20 res^=s; 21 } 22 nums[res]++; 23 for(int i=1;i<n;i++){ 24 ll x1=res^q[i]; 25 ll x2=x1^s; 26 if(x1==0){ 27 if(nums[x1]+1>=nums[x2]){ 28 res=res^q[i]^s; 29 ans-=nums[x2]; 30 nums[x2]++; 31 } 32 else{ 33 res=res^q[i]; 34 ans=ans-nums[x1]-1; 35 nums[x1]++; 36 } 37 } 38 else if(x2==0){ 39 if(nums[x1]>=nums[x2]+1){ 40 res=res^q[i]^s; 41 ans=ans-nums[x2]-1; 42 nums[x2]++; 43 } 44 else{ 45 res=res^q[i]; 46 ans-=nums[x1]; 47 nums[x1]++; 48 } 49 50 } 51 else if(nums[x1]>=nums[x2]){ 52 res=res^q[i]^s; 53 ans-=nums[x2]; 54 nums[x2]++; 55 } 56 else{ 57 res=res^q[i]; 58 ans-=nums[x1]; 59 nums[x1]++; 60 } 61 } 62 cout<<ans<<endl; 63 }