Codeforces Round 899 (Div. 2) A~D 题解 | JorbanS

A - Increasing Sequence

int solve() {
    int n; cin >> n;
    int res = 0;
    while (n --) {
        int x; cin >> x;
        res ++;
        if (res == x) res ++;
    }
    return res;
}

B - Sets and Union

int solve() {
    int n; cin >> n;
    vector<vector<int>> e(N), g(N);
    set<int> st;
    for (int i = 1; i <= n; i ++) {
        int k; cin >> k;
        while (k --) {
            int x; cin >> x;
            st.insert(x);
            e[i].push_back(x); // 集合 i 存放的数
            g[x].push_back(i); // 数 x 存放的集合序号
        }
    }
    int res = 0;
    for (auto u : st) { // 枚举删除每个变量
        vector<bool> vis(N);
        set<int> s;
        for (auto i : g[u]) vis[i] = true; // vis[i] 表示集合 i 被删除
        for (int i = 1; i <= n; i ++)
            if (!vis[i])
                for (auto j : e[i]) s.insert(j);
        res = max(res, (int)s.size());
    }
    return res;
}

C - Card Game

题解 从后面往前面删掉每一个奇数位的正数,不会影响前面的数

如果删掉位置 2 2 2 的数,那么后面所有的正数都可以被删掉

接下来只要特判位置 1 1 1 和位置 2 2 2 的数,取 m a x max max 即可

ll solve() {
    int n; cin >> n;
    ll res = 0;
    for (int i = 1; i <= n; i ++) {
        cin >> a[i];
        if (i >= 3 && a[i] > 0) res += a[i];
    }
    res += max(0, a[1] + (n > 1) * max(0, a[2]));
    return res;
}

D - Tree XOR

题意 给定一棵树,节点编号为 1 ∼ n 1\sim n 1n,点权分别为 a i a_i ai

给定操作:选定点 r r r 和数值 c c c,将 r r r 子树所有节点(包括 r r r)都异或上 c c c,代价为 r r r 子树大小与 c c c 的乘积

对于树根为 1 , 2 , . . . , n 1,2,...,n 1,2,...,n 时,使得数中的点权值全部相等,花费的最小代价

题解 考虑树根为 1 1 1 的情况,分治思想,从叶子节点往上回溯处理,每次将子节点全部异或上一个值使得与父节点相等。因为两个节点间和菊花图都只有一种情况,因此回溯上去的结果也只有一种情况,由于异或顺序时可以调换的,所以所有乱序的操作,都可以排序成回溯操作,因此有且只有一种情况能够使得所有操作后,所有点权相等

对于节点 v v v,它的父节点为 u u u,此时已经保证了 v v v 的所有子节点的点权都等于 v v v 的点权,由于有 a v ⊕ c = a u a_v\oplus c=a_u avc=au,故 c = a u ⊕ a v c=a_u\oplus a_v c=auav。由于在叶节点,所有子节点的点权已相等(只有一个点),故此分治是合法的

故树根为 1 1 1 的代价为 $\sum size_v\times (a_v\oplus a_u) \$

接下来进行换根操作:

当将根由 u u u 换成其子节点 v v v,对于 v v v 的所有节点,无需再进行异或操作,故代价减小 s i z e v × ( a v ⊕ a u ) size_v\times (a_v\oplus a_u) sizev×(avau),但需要对 u u u 这一子树的所有节点进行异或操作,代价增加 ( n − s i z e v ) × ( a v ⊕ a u ) (n-size_v)\times (a_v\oplus a_u) (nsizev)×(avau)

a n s v = a n s u + ( n − 2 × s i z e v ) × ( a v ⊕ a u ) ans_v=ans_u+(n-2\times size_v)\times (a_v\oplus a_u) ansv=ansu+(n2×sizev)×(avau)

void solve() {
    int n; cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i ++) cin >> a[i];
    vector<vector<int>> e(n + 1);
    for (int i = 1; i < n; i ++) {
        int u, v; cin >> u >> v;
        e[u].push_back(v), e[v].push_back(u);
    }
    vector<ll> sz(n + 1, 1), ans(n + 1);
    function<void(int, int)> dfs = [&](int u, int fa) {
        for (auto v : e[u]) {
            if (v == fa) continue;
            dfs(v, u);
            sz[u] += sz[v];
            ans[1] += (a[u] ^ a[v]) * sz[v];
        }
    };
    dfs(1, 1);
    function<void(int, int)> dfs2 = [&](int u, int fa) {
        for (auto v : e[u]) {
            if (v == fa) continue;
            ans[v] = ans[u] + (a[u] ^ a[v]) * (n - sz[v] * 2);
            dfs2(v, u);
        }
    };
    dfs2(1, 1);
    for (int i = 1; i <= n; i ++) cout << ans[i] << ' ';
    cout << endl;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JorbanS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值