zoukankan      html  css  js  c++  java
  • 所有区间异或的和的 一个加强

    所有区间异或的和,有三层知识点,
    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
    ",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
    ",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
    ",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
    ",sum[i]);
     95         ans+=sum[i]*qpow(2,i);
     96         ans%=MOD;
     97     }
     98    // printf("%I64d
    ",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
    ",ans);
    111     return 0;
    112 }
  • 相关阅读:
    Pycharm快捷键【mac版】
    程序解数独
    c++ map
    c++ vector 初始化二维数组
    二进制求和
    数组形式的加一
    坑题:最后一个单词的长度
    最大子序和:dp
    外观数列
    双指针消重复项
  • 原文地址:https://www.cnblogs.com/qswg/p/7892630.html
Copyright © 2011-2022 走看看