1. 程式人生 > >Codeforces - 1053 - B. Vasya and Good Sequences

Codeforces - 1053 - B. Vasya and Good Sequences

題目連結<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);
}