CF875D High Cry
阿新 • • 發佈:2018-09-22
include del -a span const class -i 計算 ger
傳送門
題目要求合法的區間個數,這裏考慮用總區間個數減去不合法的個數
假設某個數為區間最大值,那麽包含這個數的最長區間內,所有數小於他並且所有數沒有這個最大值沒有的二進制位,可以按位考慮每個數\(i\)在\(j\)這一位上向左和向右第一個二進制位為1的位置,分別記為\(l_{i,j},r_{i,j}\),然後每個數再考慮所有二進制為0的位上的\(l_{i,j},r_{i,j}\)區間的交集,左右端點為\(ll,rr\),那個這一位對答案加上\((i-ll)*(rr-j)\)
要註意,前面可能有值相同的數,導致這次計算的\(ll\)包含了上次計算過的區間,這時候要讓\(ll\)和\(a_i\)上次出現的位置取max
// luogu-judger-enable-o2 #include<bits/stdc++.h> #define LL long long #define il inline #define re register #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) #define db double #define eps (1e-8) using namespace std; const int N=200000+10; il LL rd() { re LL x=0,w=1;re char ch=0; while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();} while(ch>='0'&&ch<='9') {x=(x<<3)+(x<<1)+(ch^48);ch=getchar();} return x*w; } int n,a[N],l[N][33],r[N][33]; LL ans; map<int,int> la; int main() { n=rd(); for(int i=1;i<=n;i++) a[i]=rd(); for(int i=1;i<=n;i++) for(int j=0;j<=32;j++) l[i][j]=(a[i]&(1<<j))?i:l[i-1][j]; for(int j=0;j<=32;j++) r[n+1][j]=n+1; for(int i=n;i>=1;i--) for(int j=0;j<=32;j++) r[i][j]=(a[i]&(1<<j))?i:r[i+1][j]; for(LL i=1;i<=n;i++) { LL ll=0,rr=n+1; for(int j=0;j<=32;j++) { if(a[i]&(1<<j)) continue; ll=max(ll,l[i][j]),rr=min(rr,r[i][j]); } ll=max(ll,la[a[i]]); la[a[i]]=i; ans+=(i-ll)*(rr-i); } printf("%lld\n",1ll*n*(n+1)/2-ans); return 0; }
CF875D High Cry