NOIP模拟 字胡串(单调栈)
内网传送门
【题目分析】
只剩5分钟的时候打了一个三重循环。。。。完全没想到固定左端点减少1个n。。。。被diss了一波。。。。
对于一个区间,如果他合法,那么一定是有一个非最大数在二进制下与最大数有不同的地方,所以对于一个数,利用单调栈记录他作为最大数的区间、左右第一个至少有一位与他不同的地方,利用容斥原理计算一下统计答案即可,复杂度。
然后出现了吊打标程的dalao,利用双指针+分治做到,传送门
【代码~】
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN=1e6+10;
int n;
int a[MAXN],l[MAXN],r[MAXN];
int sta[MAXN],pos[MAXN],top;
int ll[MAXN],rr[MAXN];
int mxpos[35],maxx[35];
int Read(){
int i=0,f=1;
char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')
f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())
i=(i<<3)+(i<<1)+c-'0';
return i*f;
}
int main(){
n=Read();
for(int i=1;i<=n;++i)
a[i]=Read();
for(int i=1;i<=n;++i){
while(top&&sta[top]<=a[i])
top--;
l[i]=pos[top]+1;
sta[++top]=a[i];
pos[top]=i;
}
top=0,pos[top]=n+1;
for(int i=n;i>=1;--i){
while(top&&sta[top]<a[i])
top--;
r[i]=pos[top]-1;
sta[++top]=a[i];
pos[top]=i;
}
for(int i=1;i<=n;++i){
int x=0;
for(int mask=0;(1ll<<mask)<=a[i];++mask){
if((1ll<<mask)&a[i])
maxx[mask]=max(maxx[mask],i);
else
x=max(x,maxx[mask]);
}
ll[i]=x;
}
for(int i=0;i<=32;++i)
maxx[i]=n+1;
for(int i=n;i>=1;--i){
int x=n+1;
for(int mask=0;(1<<mask)<=a[i];++mask){
if((1<<mask)&a[i])
maxx[mask]=min(maxx[mask],i);
else
x=min(x,maxx[mask]);
}
rr[i]=x;
}
LL ans=0;
for(int i=1;i<=n;++i){
if(ll[i]>=l[i])
ans+=1ll*(ll[i]-l[i]+1)*(r[i]-i+1);
if(rr[i]<=r[i])
ans+=1ll*(i-l[i]+1)*(r[i]-rr[i]+1);
if(ll[i]>=l[i]&&rr[i]<=r[i])
ans-=1ll*(ll[i]-l[i]+1)*(r[i]-rr[i]+1);
}
cout<<ans;
return 0;
}