CF2196C1题解
传送门:https://www.luogu.com.cn/problem/CF2196C1
强化版题解:https://www.cnblogs.com/Jefferyz/p/19660578
题意简述:给你一个图的节点数,你可以询问字典序第 \(k\) 条路径是怎么样的,求出具体的每条边。
很显然路径第一条边就是一对边。我们只需要遍历所有路径然后选第一条边就行了。然而所有路径的上界是 \(O(n^4)\) 的,我们不能暴力枚举。因为按字典序排列,前两个节点相同的路径一定是连续的,我们往后二分找到前两个节点不同的第一条路径就找到了一个新边。对于每一条边向后二分。最坏询问复杂度 \(O(4m\log n)\),最大为 \(16m\),远小于 \(32(n+m)\),可以通过。这里也可以只对于第一个点进行二分,我们通过二分找到某一个点引出的路径数量,保证当且仅当一个点第一次被引出时才会进行二分,否则直接加上由上一个节点计算出的该点引出的边数量。复杂度 \(O(4n\log n)\)。
\(O(4m\log n)\) 代码:
#include <bits/stdc++.h>
const int N = 226;
using namespace std;
int a[16];
void ask(int k) {
cout << "? " << k << endl;
memset(a, 0, sizeof a);
int cnt;
cin >> cnt;
for (int i = 1; i <= cnt; ++i) cin >> a[i];
}
void solve() {
vector<pair<int, int> > ans;
int n, m = 0;
cin >> n;
int now = 1, V = n * n * n * n;
while (now <= V) {
ask(now);
if (a[2]) ++m, ans.push_back(make_pair(a[1], a[2]));
int v1 = a[1], v2 = a[2];
int l = now, r = V;
while (r >= l) {
int mid = (l + r) >> 1;
ask(mid);
if (a[1] == v1 && a[2] == v2) l = mid + 1;
else r = mid - 1;
}
now = r + 1;
}
cout << "! " << ans.size() << endl;
for (auto k: ans) cout << k.first << ' ' << k.second << endl;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) solve();
return 0;
}
\(O(4n\log n)\) 代码:
#include <bits/stdc++.h>
using namespace std;
int a[16], pos[32];
void ask(int k) {
cout << "? " << k << endl;
a[1] = 0;
int cnt;
cin >> cnt;
for (int i = 1; i <= cnt; ++i) cin >> a[i];
}
void solve() {
vector<pair<int, int> > ans;
int n;
cin >> n;
int now = 1, V = n * n * n * n + 1;
while (now <= V) {
ask(now);
int v1 = a[1];
pos[v1] = now;
if (!v1) pos[n + 1] = now;
int l = now, r = V;
while (r >= l) {
int mid = (l + r) >> 1;
ask(mid);
if (a[1] == v1) l = mid + 1;
else r = mid - 1;
}
now = r + 1;
}
for (int i = 1; i <= n; ++i) {
int p = pos[i] + 1;
while (p != pos[i + 1]) {
ask(p);
ans.push_back(make_pair(i, a[2]));
p += pos[a[2] + 1] - pos[a[2]];
}
}
cout << "! " << ans.size() << endl;
for (auto k: ans) cout << k.first << ' ' << k.second << endl;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while (T--) solve();
return 0;
}

二分,图论
浙公网安备 33010602011771号