Educational Codeforces Round 114 部分题解

A. Regular Bracket Sequences

题意:

给定整数 \(n\),要求构造恰好 \(n\) 个不同的合法括号序列,每个序列的长度为 \(2n\)

思路:

对于每个 \(i\)\(1\)\(n\),构造序列:\(i\) 个左括号,\(i\) 个右括号,接着 \(n-i\) 个左括号,\(n-i\) 个右括号。这样得到的序列都是合法的,且彼此不同。

代码

点击查看代码
void solve() {
	int n;
	cin >> n;
	for(int j=1;j<=n;j++){
		for (int i = 1; i <= j; i++) {
			cout<<"(";
		}
		for (int i = 1; i <= j; i++) {
			cout<<")";
		}
		for (int i = 1; i <= n-j; i++) {
			cout<<"(";
		}
		for (int i = 1; i <= n-j; i++) {
			cout<<")";
		}
		cout<<endl;
	}
	
}

B. Combinatorics Homework

题意:

给定三个正整数 \(a\), \(b\), \(c\) 和一个非负整数 \(m\)。判断是否存在一个字符串,恰好包含 \(a\) 个 'A',\(b\) 个 'B',\(c\) 个 'C',且其中相邻相等字母的对数恰好为 \(m\)

思路:

\(a\), \(b\), \(c\) 排序为 \(a \le b \le c\)。相邻相等对数的最大值为 \(a+b+c-3\)(即所有相同字母连续放置)。若 \(m\) 大于该值则直接输出 "NO"。
否则,考虑通过拆分连续段减少对数。每次拆分需要消耗一个其他字母作为分隔。
每构造一个相邻可以看作减少一个字母,我们构造完 \(m\) 个相邻,使得剩余字母相邻两两不同即为合法。
影响合法性的关键在于最大值,所以我们只对 \(c\) 减少个数。
设排序后 \(a \le b \le c\),若 \(m \ge c - b\),则可以将 \(c\) 拆分为与 \(b\) 相等的段数,消耗 \(c-b\) 次操作;否则仅拆分 \(m\) 次。操作后判断剩余字母能否构成无相邻相等对的字符串(即 \(a+b \ge c'-1\),其中 \(c'\) 为操作后的 \(c\))。若能则说明存在恰好 \(m\) 对相邻相等字母的字符串。

代码

点击查看代码
void solve() {
	int a,b,c,m;
	cin>>a>>b>>c>>m;
	if(a>b)swap(a,b);
	if(a>c)swap(a,c);
	if(b>c)swap(b,c);
	if(m>a-1+b-1+c-1){
		cout<<"NO"<<endl;
	}else{
		if(m>=c-max(1ll,b)){
			m-=c-max(1ll,b);
			c=max(1ll,b);	
		}else{
			c-=m;
		}
		if(a+b>=c-1){
			cout<<"YES"<<endl;
		}else{
			cout<<"NO"<<endl;
		}
	}
	
}

C. Slay the Dragon

题意:

给定 \(n\) 个英雄,每个英雄的力量为 \(a_i\)。有 \(m\) 条龙,每条龙的防御为 \(x\),攻击为 \(y\)。你需要选择恰好一个英雄去杀龙(其力量至少为 \(x\)),其余英雄防守城堡(他们的力量之和至少为 \(y\))。每次操作可以花费 1 金币将任意英雄的力量增加 1。对于每条龙独立计算最少需要花费多少金币。

思路:

设所有英雄的总力量为 S。对于一条龙 (x, y),我们有两种选择:

  1. 选择一个力量不小于 x 的英雄去杀龙,然后计算防守力量是否足够。
  2. 选择一个力量小于 x 的英雄,将他提升到 x,再计算防守力量。

将英雄力量排序后,找到第一个力量 \(\ge x\) 的英雄位置 p。若 p 存在,则考虑使用该英雄(花费只需补足防守),以及使用前一个英雄 p-1(需要先提升到 x 再补防守)。若 p 不存在(即所有英雄力量都小于 x),则只能使用最大的英雄,将他提升到 x 再补防守。取所有情况的最小值。

代码

点击查看代码
void solve() {
	int n;
	cin>>n;
	int s=0;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		s+=a[i];
	}
	sort(a+1,a+1+n);
	int m;
	cin>>m;
	for(int i=1;i<=m;i++){
		int x,y;
		cin>>x>>y;
		int p=lower_bound(a+1,a+1+n,x)-a;
		int ans=0;
		if(p>n){
			ans=x-a[n]+max(0ll,y-(s-a[n]));
		}else{
			ans=max(0ll,y-(s-a[p]));
			if(p>1){
				ans=min(ans,x-a[p-1]+max(0ll,y-(s-a[p-1])));
			}
		}
		cout<<ans<<endl;
	}
	
}

D. The Strongest Build

题意:

\(n\) 个装备槽,每个槽 \(i\)\(c_i\) 个物品,第 \(j\) 个物品提供力量值 \(a_{i,j}\),且严格递增。每个槽必须选一个物品,构建是选择物品的索引序列 \([b_1,b_2,...,b_n]\),其力量值为各物品力量值之和。给出 \(m\) 个被禁止的构建(保证至少有一个不被禁止),求不被禁止的最大力量构建,若有多个输出任意一个。

思路:

最大力量构建显然是每个槽选择最后一个物品(索引\(c_i\))。若该构建不被禁止,直接输出。否则,用优先队列按力量值降序搜索所有可能的构建。从最大构建出发,每次将某个槽的索引减1得到新构建(力量值变小),若新构建未被访问则入堆。这样按力量值从大到小检查,直到找到第一个不被禁止的构建即为答案。

代码

点击查看代码
#define PIII pair<int,vector<int>>
int a[N], c[N], p[N], b[N], f[N];
int b0[N];
vector<int>g[N];

int cnt[N];
void solve() {
	int n;
	cin >> n;
	for (int i = 0; i < n; i++) {
		cin >> c[i];
		g[i].clear();
		for (int j = 0; j < c[i]; j++) {
			int x;
			cin>>x;
			g[i].push_back(x);
		}
	}
	int m;
	cin >> m;
	set<vector<int>> ban;
	for (int i = 0; i < m; i++) {
		vector<int> b(n);
		for (int j = 0; j < n; j++) {
			cin >> b[j];
		}
		ban.insert(b);
	}
	vector<int> q(n);
	int sum = 0;
	for (int i = 0; i < n; i++) {
		q[i] = c[i];
		sum += g[i][c[i] - 1];
	}
	priority_queue<PIII, vector<PIII>, less<PIII>> p;
	set<vector<int>> vis;
	p.push({sum, q});
	vis.insert(q);
	while (!p.empty()) {
		auto [s, v] = p.top();
		p.pop();
		if (ban.count(v) == 0) {
//			cout << s << ':';
			for (int i = 0; i < n; i++) {
				cout << v[i] << " ";
			}
			cout << endl;
			return;
		}
		for (int i = 0; i < n; i++) {
			if (v[i] > 1) {
				vector<int> nxt = v;
				nxt[i]--;
				if (vis.count(nxt) == 0) {
					int ns = s - (g[i][v[i] - 1] - g[i][v[i] - 2]);
					p.push({ns, nxt});
					vis.insert(nxt);
				}
			}
		}
	}

}
posted @ 2026-02-07 11:57  ptlks  阅读(16)  评论(0)    收藏  举报