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

文章介绍了四个编程问题:G.HardBracketsProblem处理括号匹配,I.BarkleyII涉及区间划分与MEX,K.Randiaspermutationtask是排列组合优化,M.FlippingCards涉及子段和计算。文章详细展示了每个问题的解决方案和时间复杂度分析。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

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值,取最大值

还得对所以数进行离散化

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

unordered_map<int, int>mp;
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;
}
vector<int>q[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);
		vector<int>a(n + 1);
		vector<int>p;
		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;
		}
		vector<node>nod;
		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<int,int>
const int inf = 0x3f3f3f3f3f3f3f3f, N = 180 + 5, mod = 1e9 + 7;
map<vector<int>, int>mp;
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	int n, m;
	cin >> n >> m;
	vector<vector<int>>a(m+1, vector<int>(n+1));
	for (int i = 1; i <= m; i++) {
		for (int j = 1; j <= n; j++) {
			cin >> a[i][j];
		}
	}
	vector<int>res(n + 1);
	for (int i = 1; i <= m; i++) {
		map<vector<int>, int>tmp;
		tmp = mp;
		tmp[a[i]] = 1;
		for (auto w : mp) {
			vector<int>p = 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;
	//vector<int>a(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';
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值