題解 P6147 [USACO20FEB]Delegation G
阿新 • • 發佈:2021-08-07
求對所有 \(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'; }