codeforces - 1450D - Rating Compression(单调栈)

题目大意:

给你n个数,对于每个长度len (1<=len<=n)中的最小值所组成的集合是不是一个(n-i+1)的全排列,是用1表示,不是用0表示

题目思路:

1.用单调栈求出当前a[i]能控制的范围l[i],r[i] --单调栈求区间最值
2.如果对于长度len的集合中数字 num 是第一次出现,那么利用树状数组对 tree[num]++
这样就check一下 query(n-i+1)是不是大于等于n-i+1就能知道当前长度len符不符合条件

具体操作:

遍历ans[i]时候一定要倒着
拿这组样例 1 3 3 2 来说
因为我们求的是能控制的左右区间的最大范围
如果上来就去找len[1]的话是谁也找不到的,但是len=1又是符合条件的
但如果倒着遍历
先找Len=3 , num = 1 .tree[1]++ ,check — ok
len=2 , num =2 ,3 .tree[2]++,tree[3]++ ,check—ok
len =1 无 check —ok

Code:

int l[maxn],r[maxn],a[maxn],n,ans[maxn],vis[maxn],b[maxn];
int t[maxn];
vector<int>len[maxn];
int lowbit(int x) {
    
    
	return x&(-x);
}
void add(int x) {
    
    
	while(x<=n) t[x]++,x+=lowbit(x);
}
int q(int x) {
    
    
	int ans=0;
	while(x>0) {
    
    
		ans+=t[x];
		x-=lowbit(x);
	}
	return ans;
}
int main() {
    
    
	int _  = read();
	while(_--) {
    
    
		mst(vis,0);
		n=read();
		rep(i,1,n) a[i] = read(), ans[i]= t[i] =l[i] = r[i] = 0,len[i].clear();
		stack<int>st;

		for(int i=1 ; i<=n ; i++) {
    
    
			while(st.size()&&a[i]<=a[st.top()])st.pop();
			if(st.size()==0) l[i] = 1;
			else l[i] = st.top()+1;
			st.push(i);
		}
		while(st.size()) st.pop();


		for(int i= n ; i>=1 ; i--) {
    
    
			while(st.size()&&a[i]<=a[st.top()]) st.pop();
			if(st.size()==0) r[i] = n;
			else r[i] = st.top()-1;
			st.push(i);
		}
		while(st.size()) st.pop();

		rep(i,1,n) len[r[i]-l[i]+1].push_back(a[i]);

		for(int i=n ; i>=1 ; i--) {
    
    
			for(int num:len[i]) {
    
    
				vis[num]++;
				if(vis[num]==1) add(num);
			}
			int sum = q(n-i+1);
			if(sum>=n-i+1) ans[i] =1;
		}
		rep(i,1,n) cout<<ans[i];
		cout<<endl;
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wmy0536/article/details/110941490