题解:CF746G New Roads
题外话:感觉没有思路极其清晰的题解?
- 构造一棵
n 个点的深度为t 的树,以1 为根,使其中深度为i 的点有a_i 个且叶节点有k 个。或报告无解。
为了方便,我们令根节点的深度为
首先计算这棵树最多和最少有几个叶子节点,那么如果
第一个观察是无论如何构造,最后一层的节点一定是叶子节点,且第一层一定不是叶节点。
可以发现叶子最多的情况,是每一层的节点都连向上一层的同一个节点,即
除第一层外和最后一层外,每一层的叶子节点数一定不会少于
然后考虑根据
int n, k, t, a[N], sum[N];
int Id(int a, int b) { // 第 a 层的第 b 个点
return sum[a - 1] + b;
}
int mn() {
int res = a[t];
for (int i = 1; i < t; ++ i )
if (a[i] > a[i + 1]) res += a[i] - a[i + 1];
return res;
}
int mx() {
int res = a[t];
for (int i = 1; i < t; ++ i )
res += a[i] - 1;
return res;
}
int b[N];
vector<pair<int, int> > res;
void build_b() {
int lst = k - a[t];
for (int i = 2; i < t; ++ i ) {
b[i] = max(0ll, a[i] - a[i + 1]);
lst -= b[i];
}
for (int i = 2; i < t; ++ i ) {
int tmp = min(lst, a[i] - 1 - b[i]);
b[i] += tmp;
lst -= tmp;
}
}
void Luogu_UID_748509() {
fin >> n >> t >> k;
++ t;
sum[1] = 1;
a[1] = 1;
for (int i = 2; i <= t; ++ i ) fin >> a[i], sum[i] = sum[i - 1] + a[i];
if (k < mn() || k > mx()) puts("-1");
else {
build_b();
for (int i = 1; i < t; ++ i ) {
int x = a[i] - b[i];
for (int j = 1; j <= x; ++ j )
res.emplace_back(Id(i, j), Id(i + 1, j));
for (int j = x + 1; j <= a[i + 1]; ++ j )
res.emplace_back(Id(i, x), Id(i + 1, j));
}
fout << n << '\n';
for (auto t : res) fout << t.first << ' ' << t.second << '\n';
}
}