CF 876F High City 单调栈,枚举,或运算

来源:互联网 发布:孟加拉国知乎 编辑:程序博客网 时间:2024/06/05 09:06
Problem F
题意:给出长度为n的序列a,问有多少个区间[L,R]满足 a[L]|a[L+1]|...a[R] >max(a[L],...a[R]).
n<=2e5,  0<=a[i]<=1e9.


先用单调栈O(n)求出a[i]最为最大值的区间[L,R].
找到a[i]最左边(右边)a[j] 满足 a[i]|a[i-1]|..a[j] >a[i] 即a[j]二进制中存在a[i]没有的bit.[x,y].
即a[i]|a[i-1]..|a[x-1]时的值是不变的.

容易算出以a[i]为最大值时,a[L]|a[L+1]|...a[R] < max(a[L],...a[R])区间个数.左端点有i-x+1种选法 右端点有b-y+1种.

#include <bits/stdc++.h>using namespace std;typedef long long ll;const int N=2e5+20;int n,a[N],L[N],R[N];int le[32][N],rg[32][N];stack<int> s;int main(){    scanf("%d",&n);    for(int i=0;i<n;i++)        scanf("%d",&a[i]);    for(int i=0;i<n;i++)    {        while(!s.empty()&&a[s.top()]<a[i])            R[s.top()]=i-1,s.pop();        L[i]=s.empty()?0:s.top()+1;        R[i]=n-1;        s.push(i);    }    for(int j=0;j<30;j++)    {        for(int i=0;i<n;i++)        {            int h=i;            while(h<n&&((a[i]>>j)&1)==((a[h]>>j)&1))                h++;            h--;            for(int k=i;k<=h;k++)                le[j][k]=i,rg[j][k]=h;            i=h;        }    }    ll res=0;    for(int i=0;i<n;i++)    {        int l=L[i],r=R[i];        for(int j=0;j<30;j++)        {            if((a[i]>>j)&1)                continue;            l=max(l,le[j][i]);            r=min(r,rg[j][i]);        }        res+=(i-l+1ll)*(r-i+1ll);    }    ll ans=1ll*n*(n+1)/2 - res;    cout<<ans<<endl;    return 0;}


原创粉丝点击