zoukankan      html  css  js  c++  java
  • CF875D High Cry(二分+分治)

    经典问题,真难则反后算贡献

    我们发现算>难度很大,不妨考虑算=后再用总区间减去非法区间

    对于计算区间,可以考虑对于每个点维护以他为最大值的范围。

    这可以二分求取,之后在算出来的左右区间内继续二分求或值等于他本身的

    然后根据乘法原理计算贡献。注意的是,为了避免重复计算并且为了防止漏算。

    我们要特殊关注一种情况,就是当两个值相等的时候,我们计算以其中一个为最大值的时候,我们对于check函数,右边是<=,而左边是<

    这样可以不重不漏的枚举答案

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pll;
    const int N=2e5+10;
    const int inf=1e9;
    ll a[N];
    ll st[N][25];
    ll tmp[N][25];
    ll n;
    int lg[N];
    void init(int x){
        st[x][0]=a[x];
        tmp[x][0]=a[x];
        int i;
        for(i=1;i<=20;i++){
            st[x][i]=max(st[x][i-1],st[min(1ll*x+(1<<(i-1)),n)][i-1]);
            tmp[x][i]=tmp[x][i-1]|tmp[min(1ll*x+(1<<(i-1)),n)][i-1];
        }
    }
    int query(int x,int y){
        int len=lg[y-x+1];
        return (tmp[x][len]|tmp[y-(1<<len)+1][len]);
    }
    int check(int l,int r){
        int len=lg[r-l+1];
        return max(st[l][len],st[r-(1<<len)+1][len]);
    }
    ll get(int x){
        int l=1,r=x-1;
        int ans1=x;
        int ans2=x;
        while(l<r){
            int mid=l+r>>1;
            if(check(mid,x-1)<a[x]){
                r=mid;
                ans1=mid;
            }
            else
                l=mid+1;
        }
        if(check(l,x-1)<a[x]&&x!=1)
            ans1=l;
        l=ans1,r=x;
        while(l<r){
            int mid=l+r>>1;
            if(query(mid,x)==a[x]){
                r=mid;
            }
            else{
                l=mid+1;
                ans1=mid+1;
            }
        }
        int l2=x+1,r2=n;
        while(l2<r2){
            int mid=l2+r2+1>>1;
            if(check(x+1,mid)<=a[x]){
                l2=mid;
                ans2=mid;
            }
            else{
                r2=mid-1;
            }
        }
        if(check(x+1,l2)<=a[x]&&x!=n)
            ans2=l2;
        l2=x,r2=ans2;
        while(l2<r2){
            int mid=l2+r2+1>>1;
            if(query(x,mid)==a[x]){
                l2=mid;
            }
            else{
                r2=mid-1;
                ans2=mid-1;
            }
        }
        return (1ll*ans2-x+1)*(1ll*x-ans1+1);
    }
    int main(){
        ios::sync_with_stdio(false);
        int i;
        cin>>n;
        lg[1]=0;
        lg[2]=1;
        for(i=3;i<N;i++){
            lg[i]=lg[i>>1]+1;
        }
        for(i=1;i<=n;i++){
            cin>>a[i];
        }
        for(i=n;i>=1;i--){
            init(i);
        }
        ll ans=n*(n+1)/2;
        for(i=1;i<=n;i++){
            ans-=get(i);
        }
        cout<<ans<<endl;
        return 0;
    }
    View Code
    没有人不辛苦,只有人不喊疼
  • 相关阅读:
    python-通过psutil监控系统性能
    集合类和JAVA多线程
    JAVA异常和基础类库
    类设计基础与进阶
    面对对象思想
    AtCoder Beginner Contest 185
    Java概述
    友链
    牛客编程巅峰赛S2第7场
    牛客小白月赛30
  • 原文地址:https://www.cnblogs.com/ctyakwf/p/13748207.html
Copyright © 2011-2022 走看看