Codeforces - 1053 - B. Vasya and Good Sequences

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/monochrome00/article/details/83144897

题目链接<http://codeforces.com/contest/1053/problem/B>


题意:

定义一个操作:把数字中的两位进行交换。给出一个序列,问存在多少个子区间,对区间内的数字进行无限次操作后使得区间内数字的异或和为0。计算符合条件的区间数。


题解:

如果一个区间内1的个数和为奇数那一定不可取。

对于偶数的情况,如果1的个数最大的数小于等于其余数字之和,就一定能构造出来。

因为数字的范围是1e18,所以1的个数不超过60。对于区间长度不超过60的可以直接暴力,超过的可以预处理前缀和的奇偶来计算sum是偶数的个数。


#include<bits/stdc++.h>
using namespace std;
#define ll long long
const ll N=3e5+7;
ll n,a[N],sum[N],cnt[N][2];
ll x;
ll get(ll x){
    ll res=0;
    while(x){
        if(x&1) res++;
        x>>=1;
    }
    return res;
}
int main()
{
    scanf("%lld",&n);
    for(ll i=1;i<=n;i++){
        scanf("%lld",&x);
        a[i]=get(x);
        sum[i]=sum[i-1]+a[i];
    }
    for(ll i=n;i>=1;i--){
        cnt[i][0]=cnt[i+1][0];
        cnt[i][1]=cnt[i+1][1];
        if(sum[i]%2) cnt[i][1]++;
        else cnt[i][0]++;
    }
    ll ans=0;
    for(ll i=1;i<=n;i++){
        ll len=min(i+60,n);
        ll maxn=a[i];
        for(ll j=i+1;j<=len;j++){
            maxn=max(maxn,a[j]);
            if((sum[j]-sum[i-1]-maxn>=maxn)&&((sum[j]-sum[i-1])%2==0)) ans++;
        }
        ans+=cnt[len+1][sum[i-1]%2];
    }
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/monochrome00/article/details/83144897
今日推荐