Codeforces Round #635 (Div. 2)

https://codeforces.com/contest/1337

雀魂场又来啦。

A - Ichihime and Triangle

随便弄弄。

B - Kana and Dragon Quest game

随便弄弄。

C - Linova and Kingdom

首先可以得到一个观察:根必定是旅游城市,离根最远的叶子必定是工业城市。

第二个观察:若某个节点是工业城市,则其子树都是工业城市。(否则,选择其子树的一个旅游城市和其交换,答案只会更好)

每个节点维护其子树的大小,那么某个节点变成工业城市的收益就是“其到根的距离”减去“其子树的大小-1”。

vector<int> G[200005];
int pa[200005];
int de[200005];
int siz[200005];
int cnt[200005];

priority_queue<pii> PQ;

void dfs(int u, int p, int d) {
    pa[u] = p;
    de[u] = d;
    siz[u] = 1;
    cnt[u] = 0;
    for(auto &v : G[u]) {
        if(v == p)
            continue;
        dfs(v, u, d + 1);
        siz[u] += siz[v];
        cnt[u] += 1;
    }
    if(cnt[u] == 0)
        PQ.push({d, u});
    return;
}

void TestCase() {
    int n, k;
    scanf("%d%d", &n, &k);
    for(int i = 1; i <= n - 1; ++i) {
        int u, v;
        scanf("%d%d", &u, &v);
        G[u].push_back(v);
        G[v].push_back(u);
    }
    dfs(1, -1, 0);
    ll sum = 0;
    while(k--) {
        sum += PQ.top().first;
        //printf("u=%d 
", PQ.top().second);
        int p = pa[PQ.top().second];
        PQ.pop();
        cnt[p] -= 1;
        if(cnt[p] == 0)
            PQ.push({de[p] - siz[p] + 1, p});
    }
    printf("%lld
", sum);
    return;
}

现在的C题都这么复杂了吗?题解好像是直接排序或者nth_element,而不管它是不是叶子。

D - Xenia and Colorful Gems

假如枚举一个宝石作为“核心”,另外两颗宝石只能选一颗大一颗小……

int r[100005];
int g[100005];
int b[100005];
ll ans;

void Input(int *a, int n) {
    for(int i = 1; i <= n; ++i)
        scanf("%d", &a[i]);
    sort(a + 1, a + 1 + n);
    return;
}

void Solve(int *l, int nl, int *m, int nm, int *r, int nr) {
    int pl = 1, pm = 1, pr = 1;
    while(pm <= nm) {
        while(pl + 1 <= nl && l[pl + 1] <= m[pm])
            ++pl;
        while(pr <= nr && r[pr] < m[pm])
            ++pr;
        if(pr > nr)
            return;
        ll x = l[pl], y = m[pm], z = r[pr];
        ll tmp = (x - y) * (x - y) + (y - z) * (y - z) + (x - z) * (x - z);
        ans = min(ans, tmp);
        ++pm;
    }
    return;
}

void TestCase() {
    int nr, ng, nb;
    scanf("%d%d%d", &nr, &ng, &nb);
    Input(r, nr);
    Input(g, ng);
    Input(b, nb);
    ans = LINF;
    Solve(r, nr, g, ng, b, nb);
    Solve(r, nr, b, nb, g, ng);
    Solve(g, ng, r, nr, b, nb);
    Solve(g, ng, b, nb, r, nr);
    Solve(b, nb, r, nr, g, ng);
    Solve(b, nb, g, ng, r, nr);
    printf("%lld
", ans);
    return;
}

所以这为什么是D题?

*E - Kaavi and Magic Spell

题意:给一个字符串 (S) 和一个空字符串 (T) ,以及一段咒文 (P) ,每次操作选择把 (S) 的第一个字符移动到 (T) 的前面或者后面,求有多少种方法使得 (T) 拥有前缀 (P)

吐槽:我连怎么验证答案存在都不会。好难哦,看题解。

题解:对于不断两边拓展的问题需要想到区间DP。

(dp[l][r]) 为长度为 (len=r-l+1)(S) 的前缀匹配了 (P)([l,r]) 区间的方案数,则:

(dp[l][r]=sumlimits_{m=l}^{r-1}dp[l][m])

原文地址:https://www.cnblogs.com/KisekiPurin2019/p/12811339.html