Educational Codeforces Round 149 (Rated for Div. 2) 题解

https://codeforces.com/contest/1837

https://codeforces.com/contest/1837/problems

利益相关:上紫祭。

真的不要以为这道题放在 F 就不敢做。

image

image

image

ABC 题都过水,就不写了。

代码丢在这里:

A:https://codeforces.com/contest/1837/submission/207156920

B:https://codeforces.com/contest/1837/submission/207180946

C:https://codeforces.com/contest/1837/submission/207186832

D. Bracket Coloring

首先猜测一个结论:\(k \leq 2\),其中 \(k\) 是答案的颜色种数。

然后可以写一个程序验证:比如说对于每一个长度为 \(10\) 的,( 数量和 ) 数量均为 \(5\),然后枚举染色验证即可。

接下来讲如何构造方案(其实构造方案就可以证明结论):

如果左括号数量不等于右括号数量,就直接暴毙,输出 \(-1\) 即可。

否则如果 \(s\) 本身就是 beautiful 的,\(k = 1\)

否则 \(k = 2\)

构造策略:

枚举每一个左括号(下标为 \(x\)),贪心找还没有染色的最右边的右括号(下标为 \(y\)),就将 \(x, y\) 都染为颜色 \(1\)

剩下的染为颜色 \(2\)

Proof. 如果没有 () 的子序列了,那肯定都是 )(,一 reverse 就是 (),所以染两种颜色即可。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define rep(i, l, r) for(int i = l;i <= r; ++ i)
#define per(i, r, l) for(int i = r;i >= l; -- i)
//#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
int n, ans[200005];
char s[200005];
inline bool pd (string s) {
	int cnt = 0;
	int L = s.size ();
	rep (i, 0, L - 1) {
		if (s[i] == '(') cnt ++;
		else {
			if (cnt <= 0) return false;
			cnt --;
		}
	}
	if (cnt != 0) return false;
	else return true;
}
inline bool judge (string S) {
	string T = S;
	reverse (T.begin (), T.end ());
	return (pd (S) || pd (T));
}
signed main () {
	int _ = read ();
	while (_ --) {
		n = read ();
		scanf ("%s", s + 1);
		int lf = 0, rt = 0;
		rep (i, 1, n) {
			lf += (s[i] == '(');
			rt += (s[i] == ')');
		} 
		string S = "";
		rep (i, 1, n) S += s[i];
		if (lf != rt) printf ("-1\n");
		else if (judge (S)) {
			printf ("1\n");
			rep (i, 1, n) printf ("1 ");
			printf ("\n");
		}
		else {
			printf ("2\n");
			vector < int > L, R;
			L.clear (), R.clear ();
			rep (i, 1, n) {
				if (s[i] == '(') L.push_back (i);
				else R.push_back (i); 
			}
			rep (i, 1, n) ans[i] = 2;
			int ls = L.size (), xb = R.size ();
			-- xb;
			rep (i, 0, ls - 1) {
				if (L[i] <= R[xb]) ans[L[i]] = ans[R[xb]] = 1, xb --;
				else break;
			}
			rep (i, 1, n) printf ("%d ", ans[i]);
			printf ("\n");
		}
	}
	return 0;
}
// Always keep it simple and stupid

F. Editorial for Two

容易发现,答案肯定是形如:

\[f(i, x) = pre(i, x) + suf(i + 1, k - x) \]

其中 \(pre(id, x)\) 表示 \(1 \sim id\) 中前 \(x\) 小之和,如果 \(id < x\) 值就是 \(+ \infty\)

同理,\(suf(id, x)\) 表示 \(id \sim n\) 中前 \(x\) 小之和,如果 \(n - id + 1 < x\) 值就是 \(+ \infty\)

Hint. 设 \(i\)\(f(i, x)\) 的最小值对应的 \(x\) 值为 \(g_i\),那么一定有:

\[0 \leq g_1 \leq g_2 \leq \dots \leq g_n \leq k \]

Proof. 随着 \(i\) 的不断变大,\(a[1 \sim i]\) 集合会包含越来越多小的数,\(a[i + 1 \sim n]\) 集合会包含越来越少的小的数,根据贪心的原则,\(g\) 肯定是不降的。

然后 \(pre\)\(suf\) 函数就可以用 FHQ Treap 维护。

但是代码有亿点点难写,尽量自己写。

#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
#include <ext/pb_ds/hash_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
typedef long long ll;
typedef pair < int, int > PII;
typedef int itn;
mt19937 RND_MAKER (chrono :: steady_clock :: now ().time_since_epoch ().count ());
inline ll randomly (const ll l, const ll r) {return (RND_MAKER () ^ (1ull << 63)) % (r - l + 1) + l;}
#define rep(i, l, r) for(int i = l;i <= r; ++ i)
#define per(i, r, l) for(int i = r;i >= l; -- i)
#define int long long
const double pi = acos (-1);
//__gnu_pbds :: tree < Key, Mapped, Cmp_Fn = std :: less < Key >, Tag = rb_tree_tag, Node_Upadte = null_tree_node_update, Allocator = std :: allocator < char > > ;
//__gnu_pbds :: tree < PPS, __gnu_pbds :: null_type, less < PPS >, __gnu_pbds :: rb_tree_tag, __gnu_pbds :: tree_order_statistics_node_update > tr;
inline int read () {
	int x = 0, f = 0;
	char c = getchar ();
	for ( ; c < '0' || c > '9' ; c = getchar ()) f |= (c == '-');
	for ( ; c >= '0' && c <= '9' ; c = getchar ()) x = (x << 1) + (x << 3) + (c & 15);
	return !f ? x : -x;
}
const int N = 3e5 + 5, V = 1e7 + 10;
struct fhq_treap {
	int root, tot;
	struct node {int ls, rs, val, pri, siz;} tr[N];
	inline void update (int u) {tr[u].siz = tr[tr[u].ls].siz + tr[tr[u].rs].siz + 1;}
	inline void split (int u, int v, int &x, int &y) {
		if (!u) {x = y = 0; return ;}
		if (tr[u].val <= v) split (tr[u].rs, v, tr[x = u].rs, y);
		else split (tr[u].ls, v, x, tr[y = u].ls);
		update (u);
	}
	inline int merge (int x, int y) {
		if (!x || !y) return x | y;
		if (tr[x].pri < tr[y].pri) return tr[y].ls = merge (x, tr[y].ls), update (y), y;
		return tr[x].rs = merge (tr[x].rs, y), update (x), x;
	}
	inline int create (int w) {int x = ++ tot; tr[x].val = w, tr[x].pri = randomly (1, V), tr[x].siz = 1; return x;}
	inline void ins (int w) {
		int x, y; x = y = 0;
		split (root, w - 1, x, y);
		root = merge (merge (x, create (w)), y);
	}
	inline void del (int w) {
		int x, y, z; x = y = z = 0;
		split (root, w, x, z), split (x, w - 1, x, y);
		root = merge (merge (x, y = merge (tr[y].ls, tr[y].rs)), z);
	}
	inline int kth (int k) {
		int u = root;
		while (true) {
			if (k <= tr[tr[u].ls].siz) u = tr[u].ls;
			else if (k == tr[tr[u].ls].siz + 1) return tr[u].val;
			else k -= tr[tr[u].ls].siz + 1, u = tr[u].rs;
		}
	}
	inline int pre (int w) {
		int u = root, ans = 0;
		while (true) {
			if (!u) return ans;
			else if (w <= tr[u].val) u = tr[u].ls;
			else ans = tr[u].val, u = tr[u].rs;
		}
	}
	inline int nxt (int w) {
		int u = root, ans = 0;
		while (true) {
			if (!u) return ans;
			else if (w >= tr[u].val) u = tr[u].rs;
			else ans = tr[u].val, u = tr[u].ls;
		}
	}
	inline int rank (int w) {
		int x, y, ans; x = y = ans = 0;
		split (root, w - 1, x, y), ans = tr[x].siz + 1;
		return root = merge (x, y), ans; 
	}
} pref, suff;
int n, k, a[300005], f;
int pre, suf, idx;
inline int mn () {
	if (idx < f + 1 || n - idx < k - (f + 1)) return 1e18;
	int P = pre, S = suf;
	P += pref.kth (f + 1);
	S -= suff.kth (k - f);
	return max (P, S);
}
signed main () {
	int _ = read ();
	while (_ --) {
		n = read (), k = read ();
		rep (i, 1, n) a[i] = read ();
		rep (i, 1, n) suff.ins (a[i]);
		pre = suf = 0;
		rep (i, 1, k) suf += suff.kth (i);
		int ans = 1e18;
		f = 0;
		int sizp = 0, sizs = n;
		rep (i, 0, n) {
			idx = i;
			if (i >= f && n - i >= k - f) ans = min (ans, max (pre, suf));
			int cur = max (pre, suf);
			if (i >= f && n - i >= k - f) ; else cur = 1e18;
			while (f < k && cur >= mn () && mn () < 1e18) {
				pre += pref.kth (f + 1);
				suf -= suff.kth (k - f);
				f ++;
				if (i >= f && n - i >= k - f) ans = min (ans, max (pre, suf));
				cur = max (pre, suf); 
			}
			if (i == n) break;
			pref.ins (a[i + 1]), sizp ++;
			if (pref.rank (a[i + 1]) <= f) pre += a[i + 1], pre -= pref.kth (f + 1);
			int awa = 0;
			if (suff.rank (a[i + 1]) <= k - f) suf -= a[i + 1], awa = 1;
			suff.del (a[i + 1]), sizs --;
			if (awa) suf += suff.kth (k - f);
		}
		while (sizp --) pref.del (pref.kth (1));
		while (sizs --) suff.del (suff.kth (1));
		printf ("%lld\n", ans);
	}
	return 0;
}
// Always keep it simple and stupid
posted @ 2023-05-26 18:58  CountingGroup  阅读(105)  评论(3编辑  收藏  举报