所有區間異或的和,有三層知識點,
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 }