1. 程式人生 > >Codeforces Round #512 (Div. 1) B. Vasya and Good Sequences

Codeforces Round #512 (Div. 1) B. Vasya and Good Sequences

粘不過來題目,自己點開看吧QAQ

題目大意:給你一列數,現在有一種操作,就是對一個數,可以任意交換其二進位制的兩位,操作次數不限。問你有多少個字串 [ l , r ],可以經過上述操作,使該字串的異或和為0。

題解:

一段數的異或和為0,即讓這一串數二進位制下每一位的1的個數都為0。於是題目可以簡化成:先搞出來每個數的二進位制下1的個數,比如:3 4 6 7,然後每次可以挑出兩個數,讓它們都減1(即消去一位)。然後看能不能把所有數都變成0。

進一步觀察,我們發現只要最大的數小於等於剩餘的數之和即可消完。即對於一段數 max(l,r) * 2 <= sum(l,r) 且 sum(l,r)為偶數即可。

對於這個問題,我們發現任意的數的二進位制下1的個數都大於0,且小於等於64。也就是 max(l,r) 小於等於64,max(l,r)*2 <=128 ,那麼對於長度大於128的區間,一定滿足 max(l,r) * 2 <= sum(l,r) ,我們只需要找有多少個區間滿足 sum(l,r)為偶數。

對於長度小於等於128的區間,暴力判斷即可。

RMQ打錯真是沒誰了QAQ

程式碼:

#include<bits/stdc++.h>
#define LL long long
#define MAXN 300050
using namespace std;
int n,b[MAXN],cf[25],Log2[MAXN],MX[MAXN][25],s[MAXN],js[MAXN],os[MAXN];
LL a[MAXN];
void RMQ()
{
    int i,j;
    for(i=1;i<=n;i++)MX[i][0]=b[i];
    for(j=1;cf[j]<=n;j++)
    {
        for(i=1;i+cf[j]-1<=n;i++)
        {
            MX[i][j]=max(MX[i][j-1],MX[i+cf[j-1]][j-1]);
        }
    }
    /*for(i=1;i<=n;i++)
    {
        for(j=1;i+cf[j]-1<=n;j++)
        {
            MX[i][j]=max(MX[i][j-1],MX[i+cf[j-1]][j-1]);
        }
    }*/
}
int Mx(int ql,int qr)
{
    int i=Log2[qr-ql+1];
    return max(MX[ql][i],MX[qr-cf[i]+1][i]);
}
int main()
{
    int l1,i,len,l,r,mx1;
    LL aa,ans;
    scanf("%d",&n);
    cf[0]=1;for(i=1;i<=20;i++)cf[i]=cf[i-1]*2;
    for(i=1;i<=300000;i++)Log2[i]=log2(i);
    for(i=1;i<=n;i++)scanf("%lld",&a[i]);
    for(i=1;i<=n;i++)
    {
        aa=a[i];
        while(aa>0LL)
        {
            b[i]+=(int)(aa%2LL);
            aa/=2LL;
        }
    }
    s[0]=0;for(i=1;i<=n;i++)s[i]=s[i-1]+b[i];

    RMQ();

    //長度小於等於128,暴力判斷
    ans=0LL;
    for(len=1;len<=128;len++)
    {
        for(l=1;l+len-1<=n;l++)
        {
            r=l+len-1;
            mx1=Mx(l,r);
            if((s[r]-s[l-1])%2==0&&mx1*2<=s[r]-s[l-1])ans++;
        }
    }

    //長度大於128,sum一定大於等於max*2,只需要判斷sum是否是偶數
    memset(js,0,sizeof(js));
    memset(os,0,sizeof(os));
    for(i=n;i>=0;i--)
    {
        js[i]+=js[i+1];os[i]+=os[i+1];
        if(s[i]%2==0)os[i]++;
        else js[i]++;
    }
    for(l=1;l<=n;l++)
    {
        l1=l-1;r=l+128-1;
        if(r+1<=n)
        {
            if(s[l1]%2==0)
            {
                ans+=(LL)os[r+1];
            }
            else
            {
                ans+=(LL)js[r+1];
            }
        }
    }
    printf("%lld",ans);
    return 0;
}