求对所有 \(k \in [1, n-1]\) 能不能把树分成若干条长 \(k\) 的链。
《赛道修建》没学透啊,拼个链都不记得了。
NOIP2018 赛道修建中的拼链方法求得每个儿子剩下来的链长度(从下往上跨过一个点的链最多一条)后用双指针拼上。
具体地:
- 递归求解每个儿子生下来的长度并记录。
- 排序。
- 若最左和最右能恰好拼成则两个指针向中间移动。
- 若不能则记录剩下的并移动相应指针。
- 若有多个剩下就失败了。
这样直接做的复杂度是 \(O(n^2 \log n)\) 的。
这里只有约数可能可以,判一下再跑居然过了。
#include <iostream>
#include <vector>
#include <algorithm>
const int N = 100005;
int n, x, y;
std::vector<int> g[N];
int dfs(int u, int fa, int len) {
std::vector<int> a;
for (int i = 0; i < (int)g[u].size(); i++) {
int v = g[u][i];
if (v == fa) continue;
int t = dfs(v, u, len);
if (t == -1) return -1;
if (t + 1 == len) continue;
a.push_back(t+1);
}
std::sort(a.begin(), a.end());
int l = 0, r = a.size()-1, an = 0;
while (l < r) {
if (a[l] + a[r] == len) l ++, r --;
else if (an) return -1;
else if (a[l] + a[r] > len) an = a[r], r --;
else an = a[l], l ++;
}
if (l > r) return an;
else if (an) return -1;
return a[l];
}
int main() {
std::cin >> n;
if (n == 1) return 0;
for (int i = 1; i < n; i++) {
std::cin >> x >> y;
g[x].push_back(y), g[y].push_back(x);
}
std::cout << '1';
for (int i = 2; i < n; i++)
if ((n-1) % i == 0 && dfs(1, 0, i) == 0) std::cout << '1';
else std::cout << '0';
}