[九省联考 2018]秘密袭击coat

Posted NaVi_Awson

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[九省联考 2018]秘密袭击coat相关的知识,希望对你有一定的参考价值。

Description

题库链接

给出一棵 \(n\) 个点的树,每个点有点权。求所有联通块的权值 \(k\) 大和,对 \(64123\) 取模。

\(1\leq n,k\leq 1666\)

Solution

写正解是不可能的,这辈子都不可能的。只有写暴力才能维持的了生活这样子。

不妨枚举连通块内第 \(k\) 大的点。为了方便讨论,当点权相同时,点的标号越大,点优先级越高。

将优先级高于枚举的点的点权赋值为 \(1\) ,低于枚举的点的点权赋值为 \(0\) 。然后就是找包含枚举的点在内的连通块点权和 \(= k-1\) 的个数。

简易的树 \(dp\) 即可。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1666+5, yzh = 64123;

int n, k, w, d[N], u, v, root, ans, f[N][N];
struct tt {int to, next; }edge[N<<1];
int path[N], top;

void dfs(int u, int fa) {
    if (d[u] > d[root] || (d[u] == d[root] && u > root)) {
        f[u][1] = 0; for (int i = 1; i < k; i++) f[u][i+1] = f[fa][i];
    }else for (int i = 1; i <= k; i++) f[u][i] = f[fa][i];
    for (int i = path[u]; i; i = edge[i].next)
        if (edge[i].to != fa) dfs(edge[i].to, u);
    for (int i = 1; i <= k; i++) {
        f[fa][i] += f[u][i];
        if (f[fa][i] >= yzh) f[fa][i] -= yzh;
    }
}
void add(int u, int v) {edge[++top] = (tt){v, path[u]}; path[u] = top; }
void work() {
    scanf("%d%d%d", &n, &k, &w);
    for (int i = 1; i <= n; i++) scanf("%d", &d[i]);
    for (int i = 1; i < n; i++) {
        scanf("%d%d", &u, &v); add(u, v), add(v, u);
    }
    for (int i = 1; i <= n; i++) {
        root = i; int tot = 0;
        for (int j = 1; j <= n; j++) tot += bool(d[j] > d[i] || (d[j] == d[i] && j > i));
        if (tot < k-1) continue; f[i][1] = 1;
        for (int j = 2; j <= k; j++) f[i][j] = 0;
        for (int j = path[i]; j; j = edge[j].next) dfs(edge[j].to, i);
        ans += 1ll*d[i]*f[i][k]%yzh; if (ans >= yzh) ans -= yzh;
    }
    printf("%d\n", ans);
}
int main() {work(); return 0; }

以上是关于[九省联考 2018]秘密袭击coat的主要内容,如果未能解决你的问题,请参考以下文章

[九省联考 2018]秘密袭击coat

bzoj5250 [九省联考2018]秘密袭击coat 树形dp

[九省联考2018]秘密袭击coat

[九省联考2018]秘密袭击coat

解题:九省联考2018 秘密袭击CoaT

luogu P4365 [九省联考2018]秘密袭击coat