比赛链接:
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;
}