• 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
  • 相关阅读:
    Jmeter应用大全
    js防止backspace回退到上一界面(兼容各种浏览器)
    easyui部分组件获得焦点
    防止用户直接在地址栏输入URL浏览文件
    Oracle入门基础(六)一一子查询
    Oracle入门基础(五)一一多表查询
    Oracle入门基础(四)一一多行函数
    Oracle入门基础(三)一一单行函数
    Oracle入门基础(一)一一基本查询
    测试用例的设计思路
  • 原文地址:https://www.cnblogs.com/DriverLao/p/7682581.html
Copyright © 2020-2023  润新知