Codeforces 1450D - Rating Compression

1450D - Rating Compression

1450D 1800分

**题意:**给出一个数列A,通过A进行一些k ( k ∈ [ 1 , n ] ) (k \in [1,n]) (k[1,n])的构造B, b j = m i n j ≤ i ≤ j + k − 1 a i b_j = min_{j \le i \le j + k - 1}a_i bj=minjij+k1ai,问每个B数列是否为一个排列

一些想法:(乱七八糟不是正解

  • 一个数如果比较小,并且出现多次,则需要一个长度起码能包含所有该数,该数才不会出现多次
  • 一个数的影响范围为左右比它小的数内的范围,(于是我拿单调栈写了点,虽然写的好像是队列(很怪…
  • 一个数如果不存在,则 b n − i + 1 b_{n - i + 1} bni+1后就不会再成立

发现还是很乱,而且有些情况没有考虑清楚:比如第一点我刚开始觉得所有数都是这样,其实只有当它比较小的时候,CF代码怎么会这么乱呢肯定不是正解(bu

先挖个坑,有点想不明白,(纪念一下我wa1的代码(?绝了)

#include <bits/stdc++.h>
using namespace std;

const int maxn = 3e5 + 10;
vector<int> g[maxn];
int mx[maxn];
int st[maxn];
int hh, tt;
int le[maxn], ri[maxn], a[maxn];

inline void init(int n) {
    
    
	for(int i = 0; i <= n; ++ i) g[i].clear();
	mx[0] = 0;
	hh = 1, tt = 0;
}

int main() {
    
    
	int T;
	cin >> T;
	while(T--) {
    
    
		int n;
		cin >> n;
		init(n);
		
		for(int i = 1; i <= n; ++i) {
    
    
			cin >> a[i];
			g[a[i]].push_back(i); 
		}
		
		for(int i = 1; i <= n; ++i) {
    
    
			while(hh <= tt && a[st[tt]] >= a[i]) --tt;
			if(hh <= tt) le[i] = st[tt];
			else le[i] = -1;
			st[++tt] = i;
		}
		
		hh = 1, tt = 0;
		
		for(int i = n; i >= 1; --i) {
    
    
			while(hh <= tt && a[st[tt]] >= a[i]) --tt;
			if(hh <= tt) ri[i] = st[tt];
			else ri[i] = -1;
			st[++tt] = i;
		} 
		
		for(int i = 1; i <= n; ++i) {
    
    
			cout << le[i] << " ";
		}
		cout << endl;
		for(int i = 1; i <= n; ++i) {
    
    
			cout << ri[i] << " ";
		}
		cout << endl;

		for(int i = 1; i <= n; ++i) {
    
    
			if(g[i].size() < 1) {
    
    
				mx[i] = mx[i - 1];
				continue;
			}
			//int len = g[i][g[i].size() - 1] - g[i][0] + 1;
			int u = g[i][g[i].size() - 1];
			int v = g[i][0];
			int l = le[v];
			int r = ri[u];
			int len;
			if(l == -1 && r == -1) {
    
    
				len = u - v + 1;
			}
			else if(l == -1) {
    
    
				len = r - v;
			}
			else if(r == -1) {
    
    
				len = u - l;
			}
			else {
    
    
				len = r - l - 2;
			}
			len = max(1, len);
			mx[i] = max(mx[i - 1], len);
		}
		
		for(int i = 1; i <= n; ++i) {
    
    
			cout << mx[i] << " ";
		}
		cout << endl;
		
		int f = 0;
		for(int i = 1; i <= n; ++i) {
    
    
			if(g[i].size() == 0) {
    
    
				if(f == 0) f = i;
			}
			
			if(f > 0 && n - i + 1 >= f) cout << 0;
				else {
    
    
					if(i >= mx[n - i + 1]) cout << 1;
					else cout << 0;
				}
		}
		
		cout << endl;
	}
} 

然后看题解去了,正解果然不长

k = 1,和 k = n的情况显然,

关于其他的情况,因为1最小,1必须在两端中的任意一个,(然后发现可以递推下去,(

复杂度 O ( n ) O(n) O(n)

正解code

#include <bits/stdc++.h>
using namespace std;

const int maxn = 3e5 + 10;
int a[maxn];
int an[maxn], cnt[maxn];

inline void init(int n) {
    
    
	for(int i = 0; i <= n; ++i) {
    
    
		an[i] = 0;
		cnt[i] = 0;
	}
}

int main() {
    
    
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	int T;
	cin >> T;
	while(T--) {
    
    
		int n;
		cin >> n;
		init(n);
		for(int i = 1; i <= n; ++i) {
    
    
			cin >> a[i];
			cnt[a[i]]++;
		}
		
		bool f = 0;
		for(int i = 1; i <= n; ++i) {
    
    
			if(!cnt[i]) {
    
    
				f = 1;
				break;
			}
		}
		if(f) an[1] = 0;
		else an[1] = 1;
		
		if(cnt[1]) an[n] = 1; 
		
		if(!cnt[1]) {
    
    
			for(int i = 1; i <= n; ++i) {
    
    
				cout << 0;
			}
			cout << endl;
			continue;
		}
		
		int l = 1, r = n;
		int idx = 1;
		for(int i = n; i > 1; --i) {
    
    
			an[i] = 1;
			int nxt = n - i + 1;
			if(--cnt[nxt] == 0 && (a[l] == nxt || a[r] == nxt) && cnt[nxt + 1]) {
    
    
				if(a[l] == nxt) ++l;
				if(a[r] == nxt) --r;
				continue;
			}
			break;
		}
		
		for(int i = 1; i <= n; ++i) {
    
    
			cout << an[i];
		}
		cout << endl;
	}
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_39602052/article/details/110922702