• [The 2020 ICPC Asia Macau Regional Contest] I. Nim Cheater


    题目大意

    开始是一个空的多重集,然后两种操作:

    1. ADD a b: 加入一个数值为a,权值为b的元素。
    2. DEL: 删除最近一次ADD操作

    然后,每次操作过后输出要让这些a异或起来为0,要删除哪些a,且要使得b的和最小。

    题解

    如果没有题目的8M空间限制,那么我们有dp方程

    [f[i][j] = min{f[i-1][j], f[i-1][joplus a[i]]+b[i]} ]

    其中,(f[i][j])表示前i个数取一些出来异或和为j的最小值。如果遇到DEL操作,我们就回滚版本就行了,就是把i往上退一格。

    但是,有空间的限制显然是不行的,8M大约只能开2000000个int。

    因为删除就是一个回溯过程,类似dfs,考虑建树。当加入一个数,就新建一个节点,然后删除就相当于回溯,这样一棵树就出来了。然后我们每次最多就会保存一条链。但是我们会发现依然没有优化多少,因为一条链的情况就会卡掉。再考虑轻重树链剖分,一条链上最多有(log n)条轻边。然后我们想,如果是轻边,我就复制一份dp数组,如果是重边,直接滚动数组或者说覆盖。这也就是说一条链上最多会有(log n * 16384)个int,非常满足题目条件。

    代码

    //#pragma GCC optimize(3, "Ofast", "inline")
    #include <bits/stdc++.h>
    using namespace std;
    #define X first
    #define Y second
    #define PB push_back
    #define SZ(x) (int)x.size()
    #define MK make_pair
    #define ALL(x) x.begin(), x.end()
    #define lc (o<<1)
    #define rc ((o<<1)|1)
    
    void debug() {
        cerr << endl;
    }
    
    template<typename Head, typename... Tail>
    void debug(Head H, Tail... T) {
        cerr << " " << H;
        debug(T...);
    }
    
    #define dbg(...) cerr << "[" << #__VA_ARGS__ << "]:", debug(__VA_ARGS__)
    #define endl '
    '
    using LL = long long;
    
    const int _ = 5, maxn = 40000;
    
    int son[maxn+_], now, a[maxn+_], b[maxn+_], fa[maxn+_], n, tot, w[maxn+_];
    int first[maxn+_], tote = 0, ans[maxn+_], head[maxn+_];
    pair<int, int> id[maxn+_];
    int dp[800005];
    
    struct Edge {
        int y, next;
        Edge(int y=0, int next=-1): y(y), next(next) {}
    }edges[maxn+_];
    
    void addedge(int x, int y) {
        edges[tote] = Edge(y, first[x]);
        first[x] = tote++;
    }
    
    void dfs(int x) {
        son[x] = 1;
        int maxt = 0;
        w[x] = -1;
        for (int i = first[x]; i != -1; i = edges[i].next) {
            dfs(edges[i].y);
            son[x] += son[edges[i].y];
            if (maxt < son[edges[i].y]) maxt = son[edges[i].y], w[x] = edges[i].y;
        }
    }
    
    const int M = 1<<14;
    
    void dfsdp(int x, int last, int st, int xorsum) {
        if (x) {
            if (last == st) {
                for (int i = 0; i < M; ++i)
                    dp[st+M+i] = min(dp[st+i], dp[st+(i^a[x])] + b[x]);
                for (int i = 0; i < M; ++i)
                    dp[st+i] = dp[st+M+i];
            }
            else {
                for (int i = 0; i < M; ++i)
                    dp[st+i] = min(dp[last+i], dp[last+(i^a[x])] + b[x]);
            }
        }
        for (int i = head[x]; i != -1; i = id[i].Y)
            ans[id[i].X] = dp[st+xorsum];
        for (int i = first[x]; i != -1; i = edges[i].next)
            if (edges[i].y != w[x]) dfsdp(edges[i].y, st, st + M, xorsum^a[edges[i].y]);
        if (w[x] > -1) dfsdp(w[x], st, st, xorsum^a[w[x]]);
    }
    
    int main() {
        int T = 1;
        for (int kase = 1; kase <= T; ++kase) {
            scanf("%d", &n);
            tot = 0;
            memset(fa, 0, sizeof(fa));
            memset(first, -1, sizeof(first));
            memset(head, -1, sizeof(head));
            memset(id, -1, sizeof(id));
            int t = 0;
            now = 0;
            for (int i = 0; i < n; ++i) {
                char cmd[5];
                scanf("%s", cmd);
                if (cmd[0] == 'A') {
                    fa[++tot] = now;
                    addedge(now, tot);
                    now = tot;
                    scanf("%d%d", &a[now], &b[now]);
                }
                else now = fa[now];
                id[t] = MK(i, head[now]);
                head[now] = t++;
            }
            dfs(0);
            memset(dp, 0x3f, sizeof(dp));
            dp[0] = 0;
            dfsdp(0, 0, 0, 0);
            for (int i = 0; i < n; ++i)
                printf("%d
    ", ans[i]);
        }
        return 0;
    }
    
  • 相关阅读:
    2020年“安洵杯”四川省大学生信息安全技术大赛 Misc WP
    整数划分问题
    二叉树根节点到叶子节点的所有路径和
    java正则表达式
    搜狗笔试
    跟谁学0923笔试
    360 笔试0926
    度小满0920
    TreeMap 常用函数
    达达0920
  • 原文地址:https://www.cnblogs.com/albert7xie/p/15476724.html
Copyright © 2020-2023  润新知