第九届中国大学生程序设计竞赛桂林2023 China Collegiate Programming Contest (CCPC) Guilin Onsite (The 2nd Universal Cu

目录

G. Hard Brackets Problem

I. Barkley II

K. Randias permutation task

M. Flipping Cards


补题中

G. Hard Brackets Problem

注意到,如果答案存在的话,输出串一定是一个合法输入串。可以通过模拟或者后缀和来判断无解。时间复杂度 Θ(n)。

signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		string s;
		cin >> s;
		int cnt = 0;
		for (int i = 0; i < s.size(); i++) {
			if (s[i] == '(') cnt++;
			else {
				if (cnt) cnt--;
			}
		}
		if (cnt) {
			cout << "impossible\n";
		}
		else {
			cout << s << "\n";
		}
	}
}

I. Barkley II

首先先看全选的值是多少,将他赋给最终结果

然后,假设这个数组中某一个数是MEX,这时候你可以根据这个MEX对区间进行划分

比如数组是

1 2 3 4 5 6 7 8 9 10 11

4 5 6 1 7 8 9 4 5  1   5 

假设5是MEX可以划分成(1,1),(3,8),(10,10)

假设7是MEX(1,4),(6,11)

。。。

然后结果就是用这个区间不同的数减去MEX值,取最大值

还得对所以数进行离散化

求区间不同的数之间看这个吧:区间内不同数的个数_区间有多少不同的数-CSDN博客

unordered_mapmp;
struct Tree
{
	int l, r;
	int val;
}tr[4 * N];
void build(int p, int l, int r)
{
	tr[p].l = l, tr[p].r = r, tr[p].val = 0;
	if (l == r) {
		return;
	}
	int mid = l + r >> 1;
	build(p * 2, l, mid); build(p * 2 + 1, mid + 1, r);
}
void change(int p, int x, int val) {
	if (tr[p].l == tr[p].r) {
		tr[p].val = val;
		return;
	}
	int mid = tr[p].l + tr[p].r >> 1;
	if (x <= mid) change(p * 2, x, val);
	else change(p * 2 + 1, x, val);
	tr[p].val = tr[p * 2].val + tr[p * 2 + 1].val;
}
vectorq[N];
struct node {
	int l, r, val;
};
bool cmp(node& k1, node& k2) {
	return k1.r < k2.r;
}
int st[N];
int ask(int p, int l, int r)
{
	if (l <= tr[p].l && tr[p].r <= r) {
		return tr[p].val;
	}
	int mid = tr[p].l + tr[p].r >> 1;
	int sum = 0;
	if (l <= mid) sum += ask(p * 2, l, r);
	if (r > mid) sum += ask(p * 2 + 1, l, r);
	return sum;
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int T;
	cin >> T;
	while (T--)
	{
		int n, m;
		cin >> n >> m;
		build(1, 1, n);
		vectora(n + 1);
		vectorp;
		p.push_back(0);
		for (int i = 1; i <= n+1; i++) {
			st[i] = 0;
		}
		for (int i = 1; i <= n; i++) {
			cin >> a[i];
			if (a[i] <= n) st[a[i]] = 1;
			p.push_back(a[i]);
		}
		int wc = 0;
		for (int i = 1; i <= n+1; i++) {
			if (st[i] == 0) {
				wc = i;
				break;
			}
		}
		sort(p.begin(), p.end());
		p.erase(unique(p.begin(), p.end()), p.end());//离散化
		for (int i = 1; i < p.size(); i++) {
			q[i].clear(); st[i] = 0;
			q[i].push_back(0);
			mp[p[i]] = i;
		}
		vectornod;
		for (int i = 1; i <= n; i++) {
			nod.push_back({ q[mp[a[i]]].back()+1,i-1,a[i] });
			q[mp[a[i]]].push_back(i);
		}
		for (int i = 1; i < p.size(); i++) {
			nod.push_back({ q[i].back()+1,n,p[i] });
			q[i].push_back(n + 1);
		}
		sort(nod.begin(), nod.end(), cmp);
		int pos = 0;
		int maxx = (p.size() - 1 - wc);;
		for (int i = 0; i < nod.size(); i++) {
			if (nod[i].r == 0 || nod[i].l > nod[i].r) continue;
			while (pos < nod[i].r) {
				pos++;
				if (st[mp[a[pos]]]) {
					change(1, st[mp[a[pos]]], 0);
				}
				change(1, i, 1);
				st[mp[a[pos]]] = i;
			}
			maxx = max(maxx, ask(1, nod[i].l, nod[i].r) - nod[i].val);
		}
		cout << maxx << "\n";
	}
}

K. Randias permutation task

注意到答案不超过 min{2m, n!} ≤ 362880,所以任何复杂度是 O(ans) 级别的爆搜都是正确的。具体来说,令 fi 表示前 i 个排列能复合出的排列的集合,每次枚举下一个排列选不选即可。时间复杂度 Θ(nm · min(2m, n!) · log min(2m, n!))。

#define int long long//__int128 2^127-1(GCC)
#define PII pair
const int inf = 0x3f3f3f3f3f3f3f3f, N = 180 + 5, mod = 1e9 + 7;
map, int>mp;
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	vector>a(m+1, vector(n+1));
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> a[i][j];
		}
	}
	vectorres(n + 1);
	for (int i = 1; i <= m; i++) {
		map, int>tmp;
		tmp = mp;
		tmp[a[i]] = 1;
		for (auto w : mp) {
			vectorp = w.first;
			for (int j = 1; j <= n; j++) {
				res[j] = p[a[i][j]];
			}
			tmp[res]=1;
		}
		mp = tmp;
	}
	cout << mp.size() << '\n';
}

M. Flipping Cards

二分答案 w,那么就是要求 [bi ≥ w] − [ai ≥ w] 的最大子段和。时间复杂度 Θ(n log a)。

const int inf = 0x3f3f3f3f3f3f3f3f, N = 3e5 + 5, mod = 1e9 + 7;
int a[N], b[N];
int n;
int st[N], pre[N];
bool check(int x)
{
	for (int i = 1; i <= n; i++) {
		if (a[i] < x && b[i] >= x) {
			st[i] = 1;
		}
		else if (a[i] >= x && b[i] < x) {
			st[i] = -1;
		}
		else {
			st[i] = 0;
		}
		pre[i] = pre[i - 1] + st[i];
	}
	int l = 0, r = 0;
	int minn = 0, ll = 0;
	int maxx = 0, rr = 0;
	for (int i = 1; i <= n; i++) {
		if (pre[i] - pre[ll] > maxx) {
			maxx = pre[i] - pre[ll];
			l = ll + 1, r = i;
		}
		if (pre[i] < minn) {
			minn = pre[i];
			ll = i;
		}
	}
	int g = 0, s = 0;
	for (int i = 1; i <= n; i++) {
		if (i >= l && i <= r) {
			if (b[i] >= x) g++;
			else s++;
		}
		else {
			if (a[i] >= x) g++;
			else s++;
		}
	}
	if (g - s >= 0) return 1;
	else return 0;
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	//int n;
	cin >> n;
	//vectora(n + 1), b(n + 1);
	for (int i = 1; i <= n; i++) {
		cin >> a[i] >> b[i];
	}
	int l = 1, r = 1e9+10;
	while (l < r) {
		int mid = l + r >> 1;
		if (check(mid)) l = mid+1;
		else r = mid ;
	}
	if (!check(l)) l--;
	cout << l << '\n';
}

你可能感兴趣的:(算法)