zoukankan      html  css  js  c++  java
  • CF441D

    题目大意

    给出一个有n个数的序列

    求符合 区间各数或起来的数大于区间最大数 的区间的个数

    题解

    预处理出每个数每一位是0的那位左边最近的1和右边最近的1,用单调栈找出每个最大值所在的区间的左右端点,统计答案即可。

    #include<cstdio>
    #include<algorithm>
    #include<cstring> 
    #define LL long long
    using namespace std;
    const int maxn=500010,inf=2e9;
    int n,top,st[maxn],a[maxn],digit[maxn][32],pre[maxn][32],Pre[maxn],next[maxn][32],Next[maxn],cnt[maxn];
    LL ans;
    void read(int &k){
        k=0; int f=1; char c=getchar();
        while (c<'0'||c>'9')c=='-'&&(f=-1),c=getchar();
        while ('0'<=c&&c<='9')k=k*10+c-'0',c=getchar();
        k*=f;
    }
    int main(){
        read(n);
        for (int i=1;i<=n;i++){
            read(a[i]);
            for (int x=a[i];x;x>>=1) digit[i][++cnt[i]]=x&1; //处理出a[i]二进制下的每一位 
        }
        ////////////////////////////////////////////
        //pre[i][j]表示:在第j位上,第i个数为0时,左边最近的为1的位置;next[i][j]为右边最近的1的位置 
        for (int j=1;j<=30;j++){
            int last=0;
            for (int i=1;i<=n;i++)
            if (!digit[i][j]) pre[i][j]=last;
            else last=i;
        } 
        for (int j=1;j<=30;j++){
            int first=n+1;
            for (int i=n;i;i--) 
            if (!digit[i][j]) next[i][j]=first;
            else first=i;
        }
        ////////////////////////////////////////////
        //对于一个数,不合法区间的左端点为其各个为0数位上,左边最近的1的位置的最大值
        //右端点为其各个为0数位上,右边最近的1的位置的最小值
        //即对于maxnumber,它的每个为0位,不合法区间内的其他数的这一位都为0,这样区间or起来之后等于maxnumber 
        memset(Next,32,sizeof(Next)); 
        for (int i=1;i<=n;i++)
        for (int j=1;j<=30;j++) if (!digit[i][j]) 
            Pre[i]=max(Pre[i],pre[i][j]),Next[i]=min(Next[i],next[i][j]);
        //////////////////////////////////////////// 单调栈维护以a[i]为最大值的区间的左右端点 
        a[++n]=inf;
        for (int i=1;i<=n;i++){
            for (;top&&a[i]>=a[st[top]];top--){
                ans+=1LL*((i-1)-st[top]+1)*(st[top]-(st[top-1]+1)+1); //以a[st[top]]为最大值的全部区间个数 
                ans-=1LL*(st[top]-max(st[top-1]+1,Pre[st[top]]+1)+1)*(min(i-1,Next[st[top]]-1)-st[top]+1);
                //减去不合法的区间个数 
            }
            st[++top]=i;
        }
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
  • 相关阅读:
    ITMS-90809
    iOS ipa 优化减小安装大小
    Xcode 常用路径
    如何查看 Assets.car 内资源
    UILabel 实现圆角
    iOS 改变 UITextField 的 Placeholder 的字体与颜色
    ATS (App Transport Security)
    iOS semaphore 使用
    macOS 自定义 NSButton
    iOS开发——设计模式那点事
  • 原文地址:https://www.cnblogs.com/DriverLao/p/7682581.html
Copyright © 2011-2022 走看看