题解 | #骰子魔术#

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;
}
全部评论

相关推荐

在笔试的大西瓜很矫健:校招数分不用想了,这经历和学历都不够用,大厂更别想,初筛都过不了,说点不好听的小厂数分都进不去(小厂也是假数分),要两个对口实习+3个项目(或者3+2),而且要有含金量才能补一点你的学历劣势。 建议刷实习,社招找数分,校招看运气,能入行业就行,可以运营转数分
点赞 评论 收藏
分享
评论
2
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务