E题

看了官方讲解视频的思路后才写出来

1.设f[l,r]==(a l ​ & a l+1 ​ &...& a r ​ )⊕(a l ​ ∣ a l+1 ​ ∣...∣ a r ​)

2.根据f[l,r]表达式,仅观察[l,r]中二进制数第k位的情况下,同时出现1和0才能使f[l,r]的第k位是1

3.那么符合题意的区间f[l,r]的二进制数最高位1的位数必须在[k1,k2-1]中

4.用双指针或者二分预处理出数组l[k][i]:在第k位下,从第i个数第l[k][i]个数第一次同时出现0和1,即第一次出现f[l,r]在第k位下等于1

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

int n,k1,k2,a[500005],l[65][500005];

signed main()
{
    cin>>n>>k1>>k2;
    for(int i=1;i<=n;i++)cin>>a[i];
    
    if(k1>=60)
    {
        cout<<0;
        return 0;
    }
    
    int len=60;//1e18的二进制数长为60
    for(int k=0;k<len;k++)//枚举位数,然后用双指针算法处理出数组l[][]
    {
        int cnt0=0,cnt1=0;//0的个数,1的个数
        for(int i=1,j=1;j<=n;j++)
        {
            int t=((a[j]>>k)&1);
            t?cnt1++:cnt0++;
            while(cnt0 && cnt1)//同时存在0和1
            {
                l[k][i]=j;
                int t=((a[i++]>>k)&1);
                t?cnt1--:cnt0--;
            }
        }
    }
    
    //符合条件的区间:f[l,r]的二进制数最高1的位数在[k1,k2-1]
    int ans=0;
    for(int i=1;i<=n;i++)//枚举左边界
    {
        int a=n+1,b=n+1;
        for(int k=k1;k<len;k++)
        {
            if(l[k][i]==0)continue;
            if(k<=k2-1)a=min(a,l[k][i]);
            else b=min(b,l[k][i]);
        }
        if(a==n+1)continue;
        ans+=max(b-a,0LL);
    }
    cout<<ans;
    
    return 0;
}