所有区间异或的和的 一个加强

所有区间异或的和,有三层知识点,
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转移到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];
最后,计算答案是把所有区间先按位求和,即
sum[j]=sigma(dp[i][j][1]);
ans=sigma(sum[j]* 2^j)
 
 
2.求所有长度为偶数的区间的异或的和
 
长度要偶数的时候,把序列分成
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];

 
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]这个区间的异或值,求出来,再减掉就可以了
代码
  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 }

 

posted @ 2018-03-13 18:47  强势围观  阅读(1560)  评论(0编辑  收藏  举报