1. 程式人生 > 其它 >Educational Codeforces Round 6 部分題解

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;
}