NOIP模拟 字胡串(单调栈)

内网传送门

【题目分析】

只剩5分钟的时候打了一个三重循环。。。。完全没想到固定左端点减少1个n。。。。被diss了一波。。。。

对于一个区间,如果他合法,那么一定是有一个非最大数在二进制下与最大数有不同的地方,所以对于一个数,利用单调栈记录他作为最大数的区间、左右第一个至少有一位与他不同的地方,利用容斥原理计算一下统计答案即可,复杂度O(nlog^2n)

然后出现了吊打标程的dalao,利用双指针+分治做到O(nlogn)传送门

【代码~】

#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;
}

猜你喜欢

转载自blog.csdn.net/g21glf/article/details/83547811