題目鏈接:Codeforces - High Cry
我們直接計算不合法的個數,也就是枚舉每個點,當前點作爲最大值的合法區間。
作爲最大值的區間之間正反兩次單調棧即可。
然後上一個異或>now的位置,我們可以對每一個二進制位遞推預處理。
AC代碼:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=2e5+10;
int L[N],R[N],n,a[N],f[30],s[N],top; long long res;
signed main(){
cin>>n;
for(int i=1;i<=n;i++) scanf("%d",&a[i]); a[0]=2e9;
for(int i=1;i<=n;i++){
while(top&&a[s[top]]<a[i]) --top;
L[i]=s[top]; s[++top]=i;
}
top=0; a[n+1]=2e9; s[++top]=n+1;
for(int i=n;i>=1;i--){
while(top&&a[s[top]]<=a[i]) --top;
R[i]=s[top]; s[++top]=i;
}
for(int i=1;i<=n;i++){
for(int j=0;j<30;j++) if(!(a[i]>>j&1)) L[i]=max(L[i],f[j]);
for(int j=0;j<30;j++) if(a[i]>>j&1) f[j]=i;
}
for(int j=0;j<30;j++) f[j]=n+1;
for(int i=n;i>=1;i--){
for(int j=0;j<30;j++) if(!(a[i]>>j&1)) R[i]=min(R[i],f[j]);
for(int j=0;j<30;j++) if(a[i]>>j&1) f[j]=i;
}
for(int i=1;i<=n;i++) res+=1LL*(i-L[i])*(R[i]-i);
cout<<1LL*n*(n+1)/2-res;
return 0;
}