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.
Ask yourself: is there ever a sane reason to operate on a red vertex? If you only operate on black vertices, the set of red vertices only grows. That smells like the randomness can be tamed.
Suppose a black vertex currently has red neighbors. One operation on succeeds with probability , and failure changes absolutely nothing. So the expected cost to make red now is .
The problem becomes: choose an order in which black vertices become red. The cost of vertex is
Initial red vertices are permanent sources.
Remove all initially red vertices. Each black connected component is independent. Inside one black tree, an ordering is equivalent to orienting every black-black edge from the earlier colored endpoint to the later colored endpoint. Then vertex pays
where is the number of initially red neighbors.
Root a black component. Let be the minimum cost in the subtree of , where means the parent edge points into . For each child , choosing edge adds to 's denominator and uses ; choosing uses . Sort the deltas and try every possible number of incoming children.
Operating on a red vertex is never helpful. It either stays red or becomes black. That is strictly worse, because having more red vertices can only help: you can always ignore the extra red vertices and simulate any strategy.
So in an optimal strategy we only operate on black vertices. Then the red set only grows.
If a black vertex currently has red neighbors, one operation on succeeds with probability
If it fails, a black neighbor was chosen, so remains black and the entire state is unchanged. Therefore the expected number of operations needed to make red right now is
The stochastic process has been mugged in an alley and replaced by an ordering problem.
We need choose an order in which initially black vertices become red. If vertex has red neighbors before it is colored, its contribution is
Remove all initially red vertices. The remaining black vertices form a forest. Different black components do not interact, because initially red vertices are permanent sources and we never operate on them.
For a black vertex , define:
Now consider one black component, which is a tree.
Given an order of coloring its vertices, orient every black-black edge from the earlier colored endpoint to the later colored endpoint. Then every incoming black edge into represents one black neighbor that was already colored red before .
So the cost becomes
Conversely, any orientation of a tree is acyclic. If every vertex has
then a topological order of this orientation is a valid coloring order. Sources must have , so they can start from initial red neighbors.
Thus we need minimize
over orientations of each black tree.
Root a black component arbitrarily.
Let
be the minimum total cost inside the subtree of , where tells whether the parent edge contributes an incoming edge to :
For a child of , there are two choices:
If is the set of children oriented into , then
with the condition
For fixed , we should choose the children with smallest extra cost
So for each vertex:
The root has no parent, so its contribution is .
Each black-black edge contributes to exactly one delta list. Sorting all child lists costs
Memory usage is
Good enough. No drama, no Monte Carlo nonsense, no praying to floating-point gods beyond normal doubles/long doubles.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
cout << fixed << setprecision(15);
const long double INF = 1e100L;
while (T--) {
int n;
cin >> n;
string s;
cin >> s;
vector<vector<int>> g(n);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
--u; --v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> deg(n), redCnt(n, 0);
for (int v = 0; v < n; v++) {
deg[v] = (int)g[v].size();
if (s[v] == '0') {
for (int u : g[v]) {
if (s[u] == '1') redCnt[v]++;
}
}
}
vector<int> parent(n, -2);
vector<long double> dp0(n, INF), dp1(n, INF);
long double ans = 0;
for (int root = 0; root < n; root++) {
if (s[root] == '1' || parent[root] != -2) continue;
vector<int> order;
vector<int> st;
st.push_back(root);
parent[root] = -1;
while (!st.empty()) {
int v = st.back();
st.pop_back();
order.push_back(v);
for (int u : g[v]) {
if (s[u] == '1') continue;
if (u == parent[v]) continue;
if (parent[u] != -2) continue;
parent[u] = v;
st.push_back(u);
}
}
for (int it = (int)order.size() - 1; it >= 0; it--) {
int v = order[it];
vector<long double> delta;
long double base = 0;
for (int u : g[v]) {
if (s[u] == '0' && parent[u] == v) {
base += dp1[u];
delta.push_back(dp0[u] - dp1[u]);
}
}
sort(delta.begin(), delta.end());
auto calc = [&](int t) -> long double {
long double best = INF;
long double pref = 0;
int m = (int)delta.size();
for (int x = 0; x <= m; x++) {
int denominator = redCnt[v] + t + x;
if (denominator > 0) {
best = min(best, base + pref + (long double)deg[v] / denominator);
}
if (x < m) pref += delta[x];
}
return best;
};
dp0[v] = calc(0);
dp1[v] = calc(1);
}
ans += dp0[root];
}
cout << (double)ans << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
cout << fixed << setprecision(15);
const long double INF = 1e100L;
while (T--) {
int n;
cin >> n;
string s;
cin >> s;
vector<vector<int>> g(n);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
--u; --v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> deg(n), redCnt(n, 0);
for (int v = 0; v < n; v++) {
deg[v] = (int)g[v].size();
if (s[v] == '0') {
for (int u : g[v]) {
if (s[u] == '1') redCnt[v]++;
}
}
}
vector<int> parent(n, -2);
vector<long double> dp0(n, INF), dp1(n, INF);
long double ans = 0;
for (int root = 0; root < n; root++) {
if (s[root] == '1' || parent[root] != -2) continue;
vector<int> order;
vector<int> st;
st.push_back(root);
parent[root] = -1;
while (!st.empty()) {
int v = st.back();
st.pop_back();
order.push_back(v);
for (int u : g[v]) {
if (s[u] == '1') continue;
if (u == parent[v]) continue;
if (parent[u] != -2) continue;
parent[u] = v;
st.push_back(u);
}
}
for (int it = (int)order.size() - 1; it >= 0; it--) {
int v = order[it];
vector<long double> delta;
long double base = 0;
for (int u : g[v]) {
if (s[u] == '0' && parent[u] == v) {
base += dp1[u];
delta.push_back(dp0[u] - dp1[u]);
}
}
sort(delta.begin(), delta.end());
auto calc = [&](int t) -> long double {
long double best = INF;
long double pref = 0;
int m = (int)delta.size();
for (int x = 0; x <= m; x++) {
int denominator = redCnt[v] + t + x;
if (denominator > 0) {
best = min(best, base + pref + (long double)deg[v] / denominator);
}
if (x < m) pref += delta[x];
}
return best;
};
dp0[v] = calc(0);
dp1[v] = calc(1);
}
ans += dp0[root];
}
cout << (double)ans << '\n';
}
return 0;
}