九省联考 2018


一双木棋

发现状态数很少,直接搜即可。

IIIDX

不难发现这个偏序关系形成了一棵树。

本来以为直接贪心即可,即把 \(a\) 排序,然后 dfs / bfs 一遍直接安排权值,类似于这样:

void dfs1(int u) {
    sz[u] = 1;
    for (int v : e[u]) dfs1(v), sz[u] += sz[v];
}

void dfs2(int u) {
    int p = ans[u] + sz[u] - 1;
    for (int v : e[u]) ans[v] = p - sz[v] + 1, dfs2(v), p -= sz[v];
}

不出我所料,这份简单的代码没有过,被这组数据叉掉了:

2 2.0
1 1 1 2

发现这样贪心得到的结果是 1 1 1 2;而正确答案是 1 1 2 1。发现我们要做的实际上是依次从 \(1 \sim n\) 安排每一个位置上的数,安排的时候要判断剩下的所有条件能否被满足,条件即要给一些点预留一些数量的数,那么使用线段树维护即可。时间复杂度 \(\mathcal{O}(n \log n)\)。记得搜到一个点时消除其对父亲的影响。

不过送 \(55\) 分也够高了。

林克卡特树

wqs 二分,凸性不会证。

考虑把新边的权值改为 \(c\),然后做 DP。贪心好像不太行,于是考虑 DP:问题等价于求出 \(k + 1\) 条链,使得它们的权值和最大。

考虑二分给每一条链加上一个额外权值 \(c\)。我们可以设 \(f_{u, 0 / 1 / 2}\) 表示以 \(u\) 为根的子树内 \(u\) 未被选择 / 是一条链的端点 / 是一条链的中间部分时的答案,并同时记录相应的链数量即可。

时间复杂度 \(\mathcal{O}(n \log V)\)

相关