CF2061G Kevin and Teams 题解
CF2061G Kevin and Teams 题解
题目:click here
首先第一步考虑这道题如何计算 \(k\) ,另朋友关系为红边,非朋友关系为蓝边,则我们考虑为了方便地构造,可以设 \(x\) 个点组成一个红边完全图, \(n-x\) 个点组成蓝边完全图,两个之间用蓝边连接,于是对于红边,\(\left\lfloor \frac{x}{2} \right\rfloor \le k\) 我们可以得到 \(x \le 2k+1\) 而对于蓝边,我们首先用红连通块的点连接蓝色的连通块,然后再内部两两连接,于是:
\[\min\left\{x,n-x\right\}+\left\lfloor \frac{\max\left\{(n-x)-x, 0\right\}}{2} \right\rfloor \le k
\]
我们分类讨论,如果 \(n-x < x\) 那么我们可以得到
\[n-x \le k
\]
带入第一个式子得到
\[k \ge n-x \ge n - 2k - 1 \implies n \le 3k + 1 \implies k \ge \left\lceil \frac{n - 1}{3} \right\rceil = \left\lfloor \frac{n + 1}{3} \right\rfloor
\]
对于 \(n-x > x\) 我们得到
\[x+ \left\lfloor \frac{n}{2} - x\right\rfloor=\left\lfloor \frac{n}{2}\right\rfloor \le k
\]
显然是不可能存在的,于是我们可以取 \(k=\left\lfloor \frac{n+1}{3} \right\rfloor\)
接下来考虑如何构造答案,我们得到这个 \(k\) 首先可以想到是每三个节点出一个配对,考虑对于三个结点 \(a,b,c\) 如果 \((a,b) \ne (b,c)\) 那么就可以丢掉这三个点,并贡献1的答案,剩余的跑出来的答案恰好是 \(k-1\) 但如果相等,我们可以先按下不表,用同色链存下来,直到遇到下一个不同色的边,最后同色链剩余的两两配对,得到的答案一定足够,因为 \(\left\lfloor \frac{n}{2} \right\rfloor \ge \left\lfloor \frac{n+1}{3} \right\rfloor\)
代码:
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int query(int u, int v) {
cout << '?' << ' ' << u << ' ' << v << '\n';
cout.flush();
int x; cin >> x;
return x;
}
void solve() {
int n;
cin >> n;
cout << (n + 1) / 3 << '\n';
cout.flush();
stack<pair<int, int>> stk;
vector<pair<int, int>> ans0, ans1;
for (int i = 1; i <= n; i++) {
if (stk.size() == 0) {
stk.push({i, 0});
}
else if (stk.size() == 1) {
int x = query(stk.top().first, i);
stk.push({i, x});
}
else {
int x = query(stk.top().first, i);
if (stk.top().second == x) {
stk.push({i, x});
}
else {
int ed = stk.top().first; int w = stk.top().second; stk.pop();
int u = stk.top().first; stk.pop();
if (w == 0) ans0.push_back({u, ed}), ans1.push_back({ed, i});
else ans1.push_back({u, ed}), ans0.push_back({ed, i});
}
}
}
while (stk.size() >= 2) {
int ed = stk.top().first, w = stk.top().second; stk.pop();
int u = stk.top().first; stk.pop();
if (w == 0) ans0.push_back({u, ed});
else ans1.push_back({u, ed});
}
cout << "! ";
if (ans0.size() > ans1.size()) {
for (int i = 0; i < (n + 1) / 3; i++) {
cout << ans0[i].first << ' ' << ans0[i].second << ' ';
}
}
else {
for (int i = 0; i < (n + 1) / 3; i++) {
cout << ans1[i].first << ' ' << ans1[i].second << ' ';
}
}
cout << '\n';
cout.flush();
}
int main() {
int T;
cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号