比赛链接:

https://codeforces.com/contest/1630

A. And Matching

题目大意:

给了 \(n\) (n 为 2 的幂次方)个数,从 0 到 \(n - 1\),要求将其分成 \(n\) / 2 对,让每一对进行与操作之后取和等于 \(k\)\(k\) <= n - 1),输出方案。

思路:

容易知道让整个结果变成 0 的方案,0 和 n - 1 一对,1 和 n - 2 一对...
为了实现结果等于 \(k\),我们可以先让 \(k\)\(n - 1\) 组成一对,因为 \(n - 1\) 每位上全是 1,结果就是 \(k\),这样子,0 和 \(n - k - 1\) 没了匹配对象,我们让它们组一起,结果是 0,然后我们按照前面说的对称的方式让剩下的都变成 0。有种特殊情况,\(k\) = 0 的时候,特判一下就行。
接下来讨论 \(k = n - 1\) 的情况,这样子不能实现 \(k\)\(n - 1\) 组一对,我们可以让 \(k\) 变为 \(k - 1\) 和 1,这样子就能做了。这种情况下,我们改变了三个数的匹配对象,这就要求我们的 \(n\) 要大于 4。
当然,也可以让 \(k\) 变为 \(k - 2\) 和 2,\(k - 3\) 和 3 等方案,但显然 \(k - 1\) 和 1 是最优的。

代码:

#include <bits/stdc++.h>
using namespace std;
int T = 1, n, k;
void solve(){
	scanf("%d%d", &n, &k);
	if (k == n - 1){
		if (n == 4){
			cout << "-1\n";
			return;
		}
		cout << n - 1 << " " << n - 2 << "\n";
		cout << n - 3 << " " << 1 << "\n";
		cout << 0 << " " << 2 << "\n";
		for (int i = 3; i < n / 2; i++)
			cout << i << " " << n - i - 1 << "\n";
	}
	else {
		cout << k << " " << n - 1 << "\n";
		if (k != 0) cout << n - k - 1 << " " << 0 << "\n";
		for (int i = 1; i < n / 2; i++){
			if (i == k || i == n - k - 1) continue;
			cout << i << " " << n - i - 1 << "\n";
		}
	}
}
int main(){
	cin >> T;
	while(T--)
		solve();
	return 0;
}

B. Range and Partition

题目大意:

给定一个序列 \(a\),取一个范围 [x, y],将序列分成 \(k\) 段,每一段中在 [x, y] 这个范围中的数要严格大于不在该范围中的数,求使 \(y - x\) 最小的划分序列的方法。

思路:

设一个序列 \(A\),若 x <= \(a_i\) <= y,则 \(A_i\) = 1,否则等于 -1,对 \(A\) 求一个前缀和,记为序列 \(sum\),显然,我们要实现 \(sum_n\) >= k,转化一下。
\(sum_n = \sum_{i = 1}^n b_i = \sum_{i = 1}^n (-1 + 2 * [x <= a_i <= y]) >= k\),即 \(\sum_{i = 1}^n [x <= a_i <= y] >= \lceil \frac{k + n}{2} \rceil\),那么我们就可以遍历 \(x\),然后去找一个最小的 \(y - x\)
所以我们可以 \(sort\) 一下序列 \(a\),然后找到最小的区间,接着去寻找方案。
寻找方案的过程可以通过序列 \(b\)\(sum\),只要当在范围中的数大于不在范围中的数时,就分段,即该区间的和大于 0,所以该区间的 sum 等于上一个区间的 sum 加 1,这样分出的区间全满足条件。
如果区间超过了 \(k\),只需要将后面多的区间全部合并,单个区间已经满足了条件,合并的区间也会满足条件。

代码:

#include <bits/stdc++.h>
using namespace std;
#define all(x) (x).begin(), (x).end()
int T, n, k;
void solve(){
	cin >> n >> k;
	vector <int> a(n);
	for (int i = 0; i < n; ++ i)
		scanf("%d", &a[i]);
	auto b = a;
	sort(all(b));
	int x = -1, y = n + 1;
	for (int i = 0; i <= n - (n + k + 1) / 2; ++ i){
		if (b[i + (n + k + 1) / 2 - 1] - b[i] < y - x){
			x = b[i];
			y = b[i + (n + k + 1) / 2 - 1];
		}
	}
	cout << x << " " << y << "\n";
	int l = -1, s = 0, p = 0; 
	for (int i = 0; i < n; ++ i){
		s += (x <= a[i] && a[i] <= y ? 1 : -1);
		if (s > p){
			p = s;
			if (s >= 1 && s <= k - 1){
				cout << l + 2 << " " << i + 1 << "\n";
				l = i;
			}
		}
	}
	cout << l + 2 << " " << n << "\n";
}
int main(){
	cin >> T;
	while (T--)
		solve();
	return 0;
}
posted on 2022-03-01 19:25  Hamine  阅读(123)  评论(0编辑  收藏  举报