Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
The beauty can never exceed the length of the shortest root-to-leaf name. If the closest leaf has depth with the root at depth , the answer is at most .
The answer only has two real candidates: or . If the full upper bound is impossible, dropping the last layer always gives enough slack to build a common subsequence of length .
To achieve , it is enough to make every vertex at depth have the same label, for every . Then every leaf path starts with the same length- string.
Let be the number of vertices at depth . Choosing label for depth costs zeros; choosing label costs ones. Vertices deeper than are just leftover filler.
So check whether some subset sum of satisfies and . Use a bitset subset sum, with equal weights compressed by binary splitting.
Let the root have depth , and define
Some leaf name has length exactly , so no common subsequence of all leaf names can be longer than .
The whole problem is deciding whether this upper bound is possible. If yes, the answer is . If no, the answer is . That is the main trap: do not try to run LCS DP on a tree. That way lies sadness.
Checking whether is possible
Suppose we want a common subsequence
of length .
A clean way to guarantee it is:
Then every root-to-leaf path begins with exactly this string, so the LCS has length at least . Since is already the upper bound, this is optimal.
The important structural fact is that considering these depth layers loses no power. Any length- common subsequence can be viewed as choosing one ordered same-label group for each subsequence character. If some vertex in the first layers is skipped, then some descendant in its subtree must be doing the job for the relevant group. Moving that choice upward to the skipped vertex cannot make the label-count constraint worse; it only replaces a more awkward deeper choice with a layer choice. Repeating this gives the layer construction.
So only the sizes of the first depth layers matter.
Let
and
If depth is labeled , it consumes zeros. If it is labeled , it consumes ones. The vertices deeper than do not affect this common prefix, so they can absorb whatever labels are left.
Therefore is achievable iff there is a subset sum
such that
and
The first inequality says the zero-labeled important layers fit inside the zero budget. The second says the one-labeled important layers fit inside the one budget. Everything deeper is flexible filler.
Why is always achievable if is not
Use only depths for the common subsequence.
For every , every vertex at depth has a descendant at depth , because no leaf exists above depth . Hence
When assigning labels to layers through , at least one label pool has enough remaining labels for the current layer. If both zeroes and ones had fewer than labels left, together they would have fewer than labels, but the current layer plus the still-unassigned depth- layer already need at least vertices. Contradiction. So length is always doable.
Subset sum optimization
We need subset sums of the multiset
The total sum is at most . Group equal weights. If weight appears times, replace those copies with binary chunks, for example:
This preserves all possible counts from to copies of weight , but uses only items.
Then run bitset knapsack:
Finally scan reachable sums in the valid range
If one is reachable, print ; otherwise print .
The memory is , and the compressed bitset transitions are easily fast enough for the hard constraints.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXN = 200000 + 5;
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k;
vector<int> depth(n + 1), child(n + 1), cntDepth(n + 1);
cntDepth[0] = 1;
for (int v = 2; v <= n; v++) {
int p;
cin >> p;
child[p]++;
depth[v] = depth[p] + 1;
cntDepth[depth[v]]++;
}
int D = n;
for (int v = 1; v <= n; v++) {
if (child[v] == 0) D = min(D, depth[v]);
}
vector<int> weights;
int important = 0;
for (int d = 0; d <= D; d++) {
weights.push_back(cntDepth[d]);
important += cntDepth[d];
}
sort(weights.begin(), weights.end());
vector<int> items;
for (int i = 0; i < (int)weights.size();) {
int w = weights[i];
int j = i;
while (j < (int)weights.size() && weights[j] == w) j++;
int copies = j - i;
for (int take = 1; take <= copies; take <<= 1) {
items.push_back(take * w);
copies -= take;
}
if (copies > 0) items.push_back(copies * w);
i = j;
}
bitset<MAXN> dp;
dp[0] = 1;
for (int item : items) {
dp |= dp << item;
}
int lo = max(0, k - (n - important));
int hi = min(k, important);
bool can = false;
for (int x = lo; x <= hi; x++) {
if (dp[x]) {
can = true;
break;
}
}
cout << (can ? D + 1 : D) << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const int MAXN = 200000 + 5;
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n, k;
cin >> n >> k;
vector<int> depth(n + 1), child(n + 1), cntDepth(n + 1);
cntDepth[0] = 1;
for (int v = 2; v <= n; v++) {
int p;
cin >> p;
child[p]++;
depth[v] = depth[p] + 1;
cntDepth[depth[v]]++;
}
int D = n;
for (int v = 1; v <= n; v++) {
if (child[v] == 0) D = min(D, depth[v]);
}
vector<int> weights;
int important = 0;
for (int d = 0; d <= D; d++) {
weights.push_back(cntDepth[d]);
important += cntDepth[d];
}
sort(weights.begin(), weights.end());
vector<int> items;
for (int i = 0; i < (int)weights.size();) {
int w = weights[i];
int j = i;
while (j < (int)weights.size() && weights[j] == w) j++;
int copies = j - i;
for (int take = 1; take <= copies; take <<= 1) {
items.push_back(take * w);
copies -= take;
}
if (copies > 0) items.push_back(copies * w);
i = j;
}
bitset<MAXN> dp;
dp[0] = 1;
for (int item : items) {
dp |= dp << item;
}
int lo = max(0, k - (n - important));
int hi = min(k, important);
bool can = false;
for (int x = lo; x <= hi; x++) {
if (dp[x]) {
can = true;
break;
}
}
cout << (can ? D + 1 : D) << '\n';
}
}