cf1058E 思维 前缀处理

Posted wjhstudy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf1058E 思维 前缀处理相关的知识,希望对你有一定的参考价值。

题目大意:给定一个长度为 (n≤3×105)的数列ai(1ai1018)交换一个数的任意二进制位,问你可以选出多少 区间经过操作后异或和是 0 

链接:http://codeforces.com/contest/1058/problem/E

 

思路:由于二进制随意交换,那么它本身值不必考虑,只需要保存它有多少二进制为1的个数就好了。

充分必要条件:

  • 区间中二进制1的个数是偶数
  • 区间中二进制位最多的一个数的二进制个数小于等于和的一半

对于条件一 技术分享图片

所以前面的为偶数的前提下  , 根据(0,l)的奇偶性 来判断 (l,r)的奇偶性  所以 ,将所有前缀和的奇偶性统计出来  O(n)的负责度

暂且将条件一全加上  然后再在条件二中减去

因为ai <1e18 >1 的限制所以枚举大约60位 就可以截至  

 

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define pb push_back
#define fi first
#define se second
#define all(v) v.begin(),v.end()
#define forn(i,a,n) for(int i=a;i<n;++i)


const int N = 3e5+4;
ll a[N],b[N];

ll cbit(ll x){
    ll res=1;
    while(x){
        if(x&1)res++;
        x/=2;
    }
    return res-1;
}
ll sum[N];
int cnt[2];

int main(){

    int n;
    cin>>n;
    forn(i,1,n+1){
        scanf("%lld",a+i);
        b[i]= cbit(a[i]);
    }
    ll ans=0 ;

      cnt[0]=1;

    //1 (1..j-1) , j  为偶数   // 这里用公式说明一下
    forn(i,1,n+1){
        sum[i] = sum[i-1]+b[i];
        ans += cnt[sum[i]&1]; //1 (0..j) , j  为偶数   // 这里用公式说明一下

        //根据条件2 倒着减过去
        int j =i,k=i;
        ll  Max = b[i];

        while(k>=1 && j-k<=62 ){
            Max = max(Max,b[k]);
           if(  Max*2 > sum[i]-sum[k-1] && ( (sum[i]-sum[k-1] )%2==0 )  )ans--;
           k--;
        }
        cnt[sum[i]&1]++;
        //cout<<ans<<endl;

    }

    cout<<ans<<endl;

    return 0;
}

 

---恢复内容结束---

 

以上是关于cf1058E 思维 前缀处理的主要内容,如果未能解决你的问题,请参考以下文章

Covered Points Count CF1000C 思维 前缀和 贪心

CF 1196D2 RGB Substring (hard version) --- 前缀和 + 思维

CF851 D 枚举 思维

CF-295D-Greg and Caves(dp+思维)

异或前缀和——cf1186C

CF F. Shovels Shop(前缀和预处理+贪心+dp)