题解 P9096 [PA2020] Sen o podboju
upd. 修个笔误。
数据随机自然是乱搞。
考虑一个暴力 dp:
对于边
复杂度
考虑剪枝,对于
于是我们对每一个
然后这个算法就直接以最大点不到半秒的优异表现通过了这道题!
复杂度我不会严格分析,不过感性理解的话,假定 dp 数组在树和点权都均匀随机的情况下足够均匀随机,那么根据前缀最大值个数期望(也就是笛卡尔树深度期望),复杂度可以分析为
const int N = 305;
struct Edge {
int to, nxt;
Edge() {
nxt = -1;
}
};
int n, hd[N], siz[N], pnt;
long long a[N];
Edge e[N << 1];
vector <pair <long long, long long> > dp[N][N], tmp[N];
inline void AddEdge(int u, int v) {
e[++pnt].to = v;
e[pnt].nxt = hd[u];
hd[u] = pnt;
}
inline void Read() {
n = qread();
for (int i = 1;i <= n;i++) a[i] = qread();
for (int i = 1;i < n;i++) {
int u = qread(), v = qread();
AddEdge(u, v); AddEdge(v, u);
}
}
inline void Dfs(int u, int fa) {
siz[u] = 1;
for (int i = 0;i <= n;i++) dp[u][i].clear();
dp[u][0].push_back(make_pair(a[u], a[u] * a[u]));
for (int i = hd[u];~i;i = e[i].nxt) {
int v = e[i].to;
if (v != fa) {
Dfs(v, u);
for (int i = 0;i <= siz[v];i++) {
for (int j = 0;j <= siz[u];j++) {
for (auto x : dp[v][i]) {
for (auto y : dp[u][j]) {
tmp[i + j].push_back(make_pair(x.first + y.first, x.second + y.second + 2 * x.first * y.first));
tmp[i + j + 1].push_back(make_pair(y.first, x.second + y.second));
}
}
}
}
siz[u] += siz[v];
for (int i = 0;i <= siz[u];i++) {
dp[u][i].clear();
sort(tmp[i].begin(), tmp[i].end());
long long mnv = 0x3f3f3f3f3f3f3f3f;
for (int j = 0;j < tmp[i].size();j++) {
if (tmp[i][j].second < mnv) {
mnv = tmp[i][j].second;
dp[u][i].push_back(tmp[i][j]);
}
}
tmp[i].clear();
}
}
}
}