zoukankan      html  css  js  c++  java
  • Educational Codeforces Round 6 部分题解

    C. Pearls in a Row

    直接贪心做即可。

    但是注意如果最后一段不合法,要把最后一段合进上一段,如果整个序列都不合法就无解。

    #易错警示:仔细考虑无解条件,可能还有别的坑。

    const int MAXN = 3e5 + 10;
    
    int n, aa[MAXN];
    int lisan[MAXN], cnt;
    
    int nums[MAXN], tot;
    
    void Add(int x) {
        if (nums[aa[x]] == 1) ++tot;
        ++nums[aa[x]];
    }
    void Del(int x) {
        --nums[aa[x]];
        if (nums[aa[x]] == 1) --tot;
    }
    
    int main() {
        n = read();
        rep (i, 1, n) {
            aa[i] = read();
            lisan[++cnt] = aa[i];
        }
        std::sort(lisan + 1, lisan + 1 + cnt);
        cnt = (int) (std::unique(lisan + 1, lisan + 1 + cnt) - lisan - 1);
        
        int tl = 1;
        std::vector<std::pair<int, int> > anss;
        rep (i, 1, n) {
            aa[i] = (int) (std::lower_bound(lisan + 1, lisan + 1 + cnt, aa[i]) - lisan);
            Add(i);
            if (tot) {
                anss.push_back({tl, i});
                while (tl <= i) Del(tl++);
            }
        }
        if (tl != n + 1) {
            if (!anss.size()) {
                puts("-1");
                return 0;
            }
            anss[anss.size() - 1].se = n;
        }
        printf("%d\n", (int) anss.size());
        for (auto v : anss) printf("%d %d\n", v.fi, v.se);
    
        return 0;
    }
    

    D. Professor GukiZ and Two Arrays

    只做一次交换的可以直接 \(O(nm)\) 做完。

    考虑两次交换的实质是找到一对 \(a_i + a_j\) 和一对 \(b_k + b_l\) 进行交换,于是可以大力把所有的 \(a_i + a_j\)\(b_i + b_j\) 分别求出来,然后二分一下或者双指针扫一扫(类似归并排序的合并)就可以了。

    const int MAXN = 2000 + 10;
    
    int n, m;
    lli aa[MAXN], bb[MAXN];
    lli suma, sumb;
    
    struct S {
        lli sum; int a, b;
    }; std::vector<S> swpa, swpb;
    
    bool cmp(S x, S y) {
        return x.sum < y.sum;
    }
    
    std::pair<int, int> swapping[2];
    
    int main() {
        n = read(); rep (i, 1, n) suma += (aa[i] = read());
        m = read(); rep (i, 1, m) sumb += (bb[i] = read());
        rep (i, 1, n) rep (j, i + 1, n) {
            swpa.push_back({aa[i] + aa[j], i, j});
        } std::sort(ALL(swpa), cmp);
        rep (i, 1, m) rep (j, i + 1, m) {
            swpb.push_back({bb[i] + bb[j], i, j});
        } std::sort(ALL(swpb), cmp);
        
        lli tans = std::abs(suma - sumb);
        rep (i, 1, n) {
            rep (j, 1, m) {
                lli ttans = std::abs(suma - sumb + 2 * bb[j] - 2 * aa[i]);
                if (ttans < tans) {
                    tans = ttans; swapping[0] = {i, j};
                }
            }
        }
        
        int p1 = 0, p2 = 0;
        while (p1 < (int) swpa.size() && p2 < (int) swpb.size()) {
            lli tmp = suma - sumb + 2 * swpb[p2].sum - 2 * swpa[p1].sum;
            if (std::abs(tmp) < tans) {
                tans = std::abs(tmp);
                swapping[0] = {swpa[p1].a, swpb[p2].a};
                swapping[1] = {swpa[p1].b, swpb[p2].b};
            }
            if (tmp > 0) ++p1;
            else ++ p2;
        }
        printf("%lld\n", tans);
        int knds = swapping[1].fi ? 2 : (swapping[0].fi ? 1 : 0);
        printf("%d\n", knds);
        rep (i, 0, knds - 1) printf("%d %d\n", swapping[i].fi, swapping[i].se);
        return 0;
    }
    

    E. New Year Tree

    线段树维护子树信息板子题。

    #易错警示:线段树肌肉记忆真的很容易写错,特别是递归区间那一部分。

    const int MAXN = 4e5 + 10;
    
    int n, m;
    std::vector<int> G[MAXN];
    lli cols[MAXN];
    
    int dfn[MAXN], idx[MAXN], ts; int siz[MAXN];
    void dfs(int u, int fa) {
        dfn[u] = ++ts; idx[dfn[u]] = u;
        siz[u] = 1;
        forall (G[u], i) {
            int v = G[u][i];
            if (v == fa) continue;
            dfs(v, u);
            siz[u] += siz[v];
        }
    }
    
    namespace Segt {
        lli col[MAXN << 2];
        int tag[MAXN << 2];
        
        #define ls (p << 1)
        #define rs (p << 1 | 1)
        
        void Update(int p) {
            col[p] = col[ls] | col[rs];
        }
        void buildTree(int p, int l, int r, lli *cc) {
            tag[p] = -1;
            if (l == r) {
                col[p] = (1ll << cc[idx[l]]); return;
            } int mid = (l + r) >> 1;
            buildTree(ls, l, mid, cc);
            buildTree(rs, mid + 1, r, cc);
            Update(p);
        }
        void Mod(int p, int color) {
            col[p] = (1ll << color);
            tag[p] = color;
        }
        void Pushdown(int p) {
            if (tag[p] == -1) return;
            Mod(ls, tag[p]); Mod(rs, tag[p]);
            tag[p] = -1;
        }
        void Modify(int p, int l, int r, int ll, int rr, int color) {
            if (l == ll && rr == r) {
                Mod(p, color); return;
            } Pushdown(p);
            int mid = (l + r) >> 1;
            if (rr <= mid) Modify(ls, l, mid, ll, rr, color);
            else if (mid + 1 <= ll) Modify(rs, mid + 1, r, ll, rr, color);
            else {
                Modify(ls, l, mid, ll, mid, color);
                Modify(rs, mid + 1, r, mid + 1, rr, color);
            } Update(p);
        }
        lli Query(int p, int l, int r, int ll, int rr) {
            if (l == ll && rr == r) return col[p];
            Pushdown(p);
            int mid = (l + r) >> 1;
            if (rr <= mid) return Query(ls, l, mid, ll, rr);
            else if (mid + 1 <= ll) return Query(rs, mid + 1, r, ll, rr);
            else return Query(ls, l, mid, ll, mid) | Query(rs, mid + 1, r, mid + 1, rr);
        }
    }
    
    int popcount(lli x) {
        int r = 0; while (x) { r += (x & 1); x >>= 1; } return r;
    }
    
    int main() {
        n = read(); m = read();
        rep (i, 1, n) cols[i] = read();
        rep (i, 1, n - 1) {
            int u = read(); int v = read();
            G[u].push_back(v); G[v].push_back(u); 
        } dfs(1, 0);
        Segt::buildTree(1, 1, n, cols);
        while (m --> 0) {
            int t = read();
            if (t == 1) {
                int v = read(); int c = read();
                Segt::Modify(1, 1, n, dfn[v], dfn[v] + siz[v] - 1, c);
            } else {
                int v = read();
                printf("%d\n", (int) popcount(Segt::Query(1, 1, n, dfn[v], dfn[v] + siz[v] - 1)));
            }
        }
        return 0;
    }
    

    F. Xors on Segments

    考虑每次枚举左端点 \(i\),强制选 \(a_x = a_i\),设 \(f[j]\) 表示 \(a_y\)\(y \in [i + 1, j]\) 取值时 \(f(a_x, a_y)\) 的最大值(类似一个前缀最大值),然后对于每一个询问 \([l, r]\),如果 \(i\) 在这个询问的范围内,就用 \(f[r]\) 更新答案。

    const int MAXN = 5e4 + 10;
    const int MAXNM = 1e6 + 10;
    
    int n, m;
    int aa[MAXN];
    int pref[MAXNM];
    
    int f[MAXN];
    
    std::pair<int, int> qrys[MAXN];
    int ans[MAXN];
    
    int get(int x, int y) { return pref[y] ^ pref[x - 1]; }
    
    int main() {
        std::ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
        rep (i, 1, MAXNM - 5) pref[i] = pref[i - 1] ^ i;
        n = read(); m = read();
        rep (i, 1, n) {
            aa[i] = read();
        }
        rep (i, 1, m) { qrys[i].fi = read(); qrys[i].se = read(); }
        rep (i, 1, n) {
            f[i] = aa[i];
            rep (j, i + 1, n) f[j] = std::max(f[j - 1], get(std::min(aa[i], aa[j]), std::max(aa[i], aa[j])));
            rep (j, 1, m) {
                if (qrys[j].fi <= i && i <= qrys[j].se) ans[j] = std::max(ans[j], f[qrys[j].se]);
            }
        }
        rep (i, 1, m) printf("%d\n", ans[i]);
        return 0;
    }
    
  • 相关阅读:
    PLSQL登录弹出空白框如何解决
    mongodb常用命令
    js多线程?
    Rhino -- 基于java的javascript实现
    [原创]在Docker上部署mongodb分片副本集群。
    [原创]在Linux系统Ubuntu14.04上安装部署docker。
    [原创]Win7、Win8、Win10始终以管理员身份运行程序。
    [原创]WPF应用MediaPlayer播放声音断续、不全解决方案
    [原创]C#引用C++编译的dll
    [原创]导出CSV文件,特殊字符处理。
  • 原文地址:https://www.cnblogs.com/handwer/p/15433910.html
Copyright © 2011-2022 走看看