所有区间异或的和的 一个加强
所有区间异或的和,有三层知识点,
1.求所有区间的异或的和
2.求所有长度为偶数的区间的异或的和
3.求所有长度为偶数且在m以内的区间的异或的和
大成之后即可轻松做出这题https://www.nowcoder.com/acm/contest/35/B
1.求所有区间的异或的和
2.求所有长度为偶数的区间的异或的和
3.求所有长度为偶数且在m以内的区间的异或的和
大成之后即可轻松做出这题https://www.nowcoder.com/acm/contest/35/B
1.求所有区间的异或的和
要用到位运算中用很经典的方法,按照位拆分,因为所有的位运算都是以位为最小单位进行的,不同的位之间不会互相干扰
令dp[i][j][0],1<=i<=n,0<=j<30
代表以i的右端点的所有区间的异或的和,在这位2^j 上0的个数
dp[i][j][1],1<=i<=n,0<=j<30
代表以i的右端点的所有区间的异或的和,在这位2^j 上1的个数
代表以i的右端点的所有区间的异或的和,在这位2^j 上0的个数
dp[i][j][1],1<=i<=n,0<=j<30
代表以i的右端点的所有区间的异或的和,在这位2^j 上1的个数
当由i转移到i+1时
所有以i为右端点的区间都要异或上a[i]
所以 若 a[i] 在 2^j这位上为1,则有
dp[i+1][j][0]=dp[i][j][1]+1;
dp[i+1][j][1]=dp[i][j][0];
否则
dp[i+1][j][0]=dp[i][j][0]+1;
dp[i+1][j][1]=dp[i][j][1];
所有以i为右端点的区间都要异或上a[i]
所以 若 a[i] 在 2^j这位上为1,则有
dp[i+1][j][0]=dp[i][j][1]+1;
dp[i+1][j][1]=dp[i][j][0];
否则
dp[i+1][j][0]=dp[i][j][0]+1;
dp[i+1][j][1]=dp[i][j][1];
最后,计算答案是把所有区间先按位求和,即
sum[j]=sigma(dp[i][j][1]);
ans=sigma(sum[j]* 2^j)
ans=sigma(sum[j]* 2^j)
2.求所有长度为偶数的区间的异或的和
长度要偶数的时候,把序列分成
1 3 5 7 9
2 4 6 8……
每次异或 a[i]^a[i-1]即可
1 3 5 7 9
2 4 6 8……
每次异或 a[i]^a[i-1]即可
转移方程如下
当由i-2转移到i时。
若 a[i]^a[i-1]在 2^j这位上为1,则有
dp[i][j][0]=dp[i-2][j][1]+1;
dp[i][j][1]=dp[i-2][j][0];
否则
dp[i][j][0]=dp[i-2][j][0]+1;
dp[i][j][1]=dp[i-2][j][1];
若 a[i]^a[i-1]在 2^j这位上为1,则有
dp[i][j][0]=dp[i-2][j][1]+1;
dp[i][j][1]=dp[i-2][j][0];
否则
dp[i][j][0]=dp[i-2][j][0]+1;
dp[i][j][1]=dp[i-2][j][1];
3.求所有长度为偶数且在m以内的区间的异或的和
最后限制区间长度要在m以内时,(m为偶数)
令dp[i][j][0],1<=i<=n,0<=j<30
代表以i的右端点的所有长度不超过m长度为偶数的区间的异或的和,在这位2^j 上0的个数
dp[i][j][1],1<=i<=n,0<=j<30
代表以i的右端点的所有长度不超过m长度为偶数的区间的异或的和,在这位2^j 上1的个数
当由i-2转移到i时。
若 a[i]^a[i-1]在 2^j这位上为1,则有
dp[i][j][0]=dp[i-2][j][1]+1;
dp[i][j][1]=dp[i-2][j][0];
否则
dp[i][j][0]=dp[i-2][j][0]+1;
dp[i][j][1]=dp[i-2][j][1];
当用上面这个转移方程 可能会多包含一个无效区间长度为m+2的 [i-m-1,i]
所以还要把 [i-m-1,i]这个区间的异或值,求出来,再减掉就可以了
令dp[i][j][0],1<=i<=n,0<=j<30
代表以i的右端点的所有长度不超过m长度为偶数的区间的异或的和,在这位2^j 上0的个数
dp[i][j][1],1<=i<=n,0<=j<30
代表以i的右端点的所有长度不超过m长度为偶数的区间的异或的和,在这位2^j 上1的个数
当由i-2转移到i时。
若 a[i]^a[i-1]在 2^j这位上为1,则有
dp[i][j][0]=dp[i-2][j][1]+1;
dp[i][j][1]=dp[i-2][j][0];
否则
dp[i][j][0]=dp[i-2][j][0]+1;
dp[i][j][1]=dp[i-2][j][1];
当用上面这个转移方程 可能会多包含一个无效区间长度为m+2的 [i-m-1,i]
所以还要把 [i-m-1,i]这个区间的异或值,求出来,再减掉就可以了
代码
1 #include<stdio.h> 2 #include<algorithm> 3 #include<map> 4 #include<string.h> 5 using namespace std; 6 const long long MOD=1e9+7; 7 int a[200005],d[200005]; 8 int dp[200004][32][2]; 9 long long qpow(int a,int n) 10 { 11 long long ans=1; 12 long long temp=a; 13 while(n) 14 { 15 if(n&1) 16 { 17 ans=ans*temp%MOD; 18 } 19 temp=temp*temp%MOD; 20 n>>=1; 21 } 22 return ans; 23 } 24 int cal(int n,int m) 25 { 26 // printf("m=%d\n",m); 27 if(m==0) 28 return 0; 29 memset(dp,0,sizeof(dp)); 30 memset(d,0,sizeof(d)); 31 d[1]=a[1]; 32 int i,j=0,x,temp; 33 long long sum[32]= {0},ans=0; 34 for(i=2; i<=n; i++) 35 { 36 d[i]=d[i-1]^a[i]; 37 j=0; 38 x=a[i]^a[i-1]; 39 while(j<30) 40 { 41 if(x&1) 42 { 43 dp[i][j][1]++; 44 if(i>=2) 45 { 46 dp[i][j][1]+=dp[i-2][j][0]; 47 dp[i][j][0]+=dp[i-2][j][1]; 48 } 49 } 50 else 51 { 52 dp[i][j][0]++; 53 if(i>=2) 54 { 55 dp[i][j][1]+=dp[i-2][j][1]; 56 dp[i][j][0]+=dp[i-2][j][0]; 57 } 58 } 59 j++; 60 x>>=1; 61 } 62 if(i>=m+2) 63 { 64 j=0; 65 x=d[i]^d[i-m-2]; 66 //printf("[%d %d]=%d\n",i-m-1,i,x); 67 while(j<30) 68 { 69 if(x&1) 70 { 71 dp[i][j][1]--; 72 } 73 else 74 { 75 dp[i][j][0]--; 76 } 77 j++; 78 x>>=1; 79 } 80 } 81 temp=0; 82 for(j=0; j<30; j++) 83 { 84 temp+=dp[i][j][1]*qpow(2,j); 85 temp%=MOD; 86 } 87 // printf("s=%d\n",temp); 88 for(j=0; j<30; j++) 89 sum[j]+=dp[i][j][1]; 90 91 } 92 for(i=0; i<30; i++) 93 { 94 // printf("%I64d\n",sum[i]); 95 ans+=sum[i]*qpow(2,i); 96 ans%=MOD; 97 } 98 // printf("%I64d\n",ans); 99 return ans; 100 } 101 int main() 102 { 103 int i,j,k,n,m,x,l,r,s; 104 int ans=0; 105 scanf("%d%d%d",&n,&l,&r); 106 for(i=1; i<=n; i++) 107 scanf("%d",&a[i]); 108 ans=cal(n,r/2*2)-cal(n,(l-1)/2*2); 109 ans=(ans%MOD+MOD)%MOD; 110 printf("%d\n",ans); 111 return 0; 112 }