Farmer John's farm consists of NN pastures (2≤N≤1052≤N≤105) connected by N−1N−1 roads, so that any pasture is reachable from any other pasture. That is, the farm is a tree. But after 28 years of dealing with the tricky algorithmic problems that inevitably arise from trees, FJ has decided that a farm in the shape of a tree is just too complex. He believes that algorithmic problems are simpler on paths.
Thus, his plan is to partition the set of roads into several paths, and delegate responsibility for each path to a worthy farm hand. To avoid contention, he wants each path to be the same length. He wonders for which lengths there exists such a partition.
More precisely, for each 1≤K≤N−11≤K≤N−1, help Farmer John determine whether the roads can be partitioned into paths of length exactly KK.
The first line contains a single integer NN.The next N−1N−1 lines each contain two space-separated integers aa and bb describing an edge between vertices aa and bb. Each of aa and bb is in the range 1…N1…N.
Output a bit string of length N−1.N−1. For each 1≤K≤N−1,1≤K≤N−1, the KKth bit of this string from the left should equal one if it is possible to partition the edges of the tree into paths of length exactly KK and 00 otherwise.
13 1 2 2 3 2 4 4 5 2 6 6 7 6 8 8 9 9 10 8 11 11 12 12 13
111000000000
It is possible to partition this tree into paths of length KK for K=1,2,3.K=1,2,3. For K=3K=3, a possible set of paths is as follows:
Problem credits: Mark Gordon and Dhruv Rohatgi
[/hide]
(Analysis by Benjamin Qi)
Root the tree at 11. We will do DP on subtrees.
First, observe that the answer is "no" if N−1N−1 is not divisible by K.K. Otherwise, we wish to write a function dfs(x)dfs(x) which will check whether it is possible to partition the subtree corresponding to vertex xx into paths of length KK and possibly an extra one of length less than KK with one endpoint at xx. If possible, this function will return the length of the extra path. Otherwise, the function will return −1−1.
First, we should call dfs(t)dfs(t) for all children tt of x.x. If any of these return −1,−1, then dfs(x)dfs(x) should also return −1.−1. Otherwise, we have a path of length dfs(t)+1dfs(t)+1 with one endpoint at x.x. After doing this, we should pair up as many of the paths whose lengths are in (0,K)(0,K) as possible. If there is more than one unpaired path remaining after this process, return −1−1.
Otherwise, return the length of the unpaired path, or zero if none exists. Note that if dfs(x)≠−1,dfs(x)≠−1, then its return value is equal to the remainder when the number of edges in the subtree corresponding to xx is divided by K,K, which is invariant regardless of how exactly we choose the paths of length KK.
For a fixed K,K, we can check whether it is possible to split the tree into paths of length KK in O(N)O(N) time, allowing us to solve the problem in O(N⋅(# of divisors of N)).O(N⋅(# of divisors of N)). However, several solutions with this complexity ended up receiving TLE on test case 33, where N=83161N=83161 and N−1N−1 has 128128 divisors. One option is to deal with the star case separately. Another is to write a checker that does not use recursion and is a constant factor faster, demonstrated below.
#include "bits/stdc++.h" using namespace std; void setIO(string s) { ios_base::sync_with_stdio(0); cin.tie(0); freopen((s+".in").c_str(),"r",stdin); freopen((s+".out").c_str(),"w",stdout); } #define f first #define s second const int MOD = 1e9+7; const int MX = 1e5+5; int N,sub[MX]; vector<int> adj[MX], num[MX]; bool bad = 0; void dfs(int a, int b) { sub[a] = 1; for(auto& t: adj[a]) if (t != b) { dfs(t,a); sub[a] += sub[t]; num[a].push_back(sub[t]); } if (sub[a] != N) num[a].push_back(N-sub[a]); } int cur[MX]; // basically unordered map bool ok(int K) { if ((N-1)%K != 0) return 0; for (int i = 0; i < K; ++i) cur[i] = 0; for (int i = 1; i <= N; ++i) { int cnt = 0; for (auto& t: num[i]) { int z = t%K; if (z == 0) continue; if (cur[K-z]) cur[K-z] --, cnt --; else cur[z] ++, cnt ++; } if (cnt) return 0; // paths don't pair up } return 1; } int main() { setIO("deleg"); cin >> N; for (int i = 1; i < N; ++i) { int a,b; cin >> a >> b; adj[a].push_back(b), adj[b].push_back(a); } dfs(1,0); for (int i = 1; i < N; ++i) { if (ok(i)) cout << 1; else cout << 0; } cout << "\n"; }
[/hide]
翰林课程体验,退费流程快速投诉邮箱: yuxi@linstitute.net 沪ICP备2023009024号-1