Codeforces Round #526 (Div. 1) – 解题报告

A – The Fair Nut and the Best Path

sb 树形 DP。

// CF1083A.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 3e5 + 200;

typedef long long ll;

const ll INF = 0x3f3f3f3f3f3f3f3f;

int n, current, head[MAX_N], wi[MAX_N];
ll dp[MAX_N], gans;

struct edge
{
    int to, nxt, weight;
} edges[MAX_N << 1];

void addpath(int src, int dst, int weight)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    edges[current].weight = weight, head[src] = current++;
}

void dfs(int u, int fa)
{
    ll biggest = -1, sbiggest = -1;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        if (edges[i].to != fa)
        {
            dfs(edges[i].to, u);
            ll tmp = dp[edges[i].to] - edges[i].weight;
            if (tmp > biggest)
                swap(biggest, sbiggest), biggest = tmp;
            else if (tmp > sbiggest)
                sbiggest = tmp;
        }
    dp[u] = wi[u];
    if (biggest != -1 && sbiggest != -1)
        gans = max(gans, wi[u] + biggest + sbiggest);
    if (biggest != -1)
        dp[u] += biggest;
    gans = max(gans, dp[u]);
}

int main()
{
    memset(head, -1, sizeof(head));
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%d", &wi[i]), gans = max(gans, 1LL * wi[i]);
    for (int i = 1, u, v, w; i <= n - 1; i++)
        scanf("%d%d%d", &u, &v, &w), addpath(u, v, w), addpath(v, u, w);
    dfs(1, 0), printf("%lld\n", gans);
    return 0;
}

B – The Fair Nut and Strings

可以很容易发现这东西最后等于 Trie 树的节点个数,然后我们就可以利用 01 Trie 的性质,不停地扩充节点个数即可。

// CF1083B.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 5e5 + 200;

typedef long long ll;

int n, k;
char S[MAX_N], T[MAX_N];

int main()
{
    scanf("%d%d%s%s", &n, &k, S + 1, T + 1);
    ll gans = 0, pans = 1;
    for (int i = 1; i <= n; i++)
    {
        pans <<= 1;
        if (S[i] == 'b')
            pans--;
        if (T[i] == 'a')
            pans--;
        if (pans >= k)
        {
            gans += 1LL * k * (n - i + 1);
            break;
        }
        gans += pans;
    }
    printf("%lld\n", gans);
    return 0;
}

C – Max Mex

我们可以搞一颗线段树,关键字为 mex 值。这颗线段树需要维护每一个 mex 区间所能代表的路径。这个东西可以通过 LCA + 深度判断进行操作。询问和修改直接在线段树上做正常操作即可。

// CF1083C.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 4e5 + 200;

int n, q, head[MAX_N], current, dep[MAX_N], st[20][MAX_N], wi[MAX_N], ptot, up[MAX_N], pos[MAX_N], log2_[MAX_N], bucket[MAX_N];

struct edge
{
    int to, nxt;
} edges[MAX_N << 1];

struct node
{
    int u, v;
} nodes[MAX_N << 2];

char nc()
{
    static char buffer[1 << 20], *p1, *p2;
    return p1 == p2 && (p2 = (p1 = buffer) + fread(buffer, 1, 1 << 20, stdin), p1 == p2) ? EOF : *p1++;
}

int read()
{
    int x = 0, f = 1;
    char c = nc();
    while (!isdigit(c))
        f = (c == '-' ? -1 : f), c = nc();
    while (isdigit(c))
        x = (x << 3) + (x << 1) + c - '0', c = nc();
    return x * f;
}

void addpath(int src, int dst)
{
    edges[current].to = dst, edges[current].nxt = head[src];
    head[src] = current++;
}

void dfs(int u)
{
    dep[u] = dep[up[u]] + 1, st[0][++ptot] = u, pos[u] = ptot;
    for (int i = head[u]; i != -1; i = edges[i].nxt)
        dfs(edges[i].to), st[0][++ptot] = u;
}

int getLCA(int x, int y)
{
    if (pos[x] > pos[y])
        swap(x, y);
    int len = pos[y] - pos[x] + 1, d = log2_[len];
    int lft = st[d][pos[x]], rig = st[d][pos[y] - (1 << d) + 1];
    return dep[lft] < dep[rig] ? lft : rig;
}

int getDist(int x, int y) { return dep[x] + dep[y] - (dep[getLCA(x, y)] << 1); }

node mergeNode(node u, int w)
{
    if (u.u == -1 || w == -1)
        return node{-1, -1};
    int d1 = getDist(u.u, u.v), d2 = getDist(u.u, w), d3 = getDist(u.v, w);
    return d1 == d2 + d3 ? u : ((d1 + d3 == d2) ? node{u.u, w} : (d1 + d2 == d3 ? node{u.v, w} : node{-1, -1}));
}

node pushup(node lson, node rson) { return mergeNode(mergeNode(lson, rson.u), rson.v); }

#define lson (p << 1)
#define rson ((p << 1) | 1)
#define mid ((l + r) >> 1)

void build(int l, int r, int p)
{
    if (l == r)
        return (void)(nodes[p] = node{bucket[l], bucket[l]});
    build(l, mid, lson), build(mid + 1, r, rson);
    nodes[p] = pushup(nodes[lson], nodes[rson]);
}

void update(int qx, int l, int r, int p)
{
    if (l == r)
        return (void)(nodes[p] = node{bucket[l], bucket[l]});
    if (qx <= mid)
        update(qx, l, mid, lson);
    else
        update(qx, mid + 1, r, rson);
    nodes[p] = pushup(nodes[lson], nodes[rson]);
}

int query(node &tmp, int l, int r, int p)
{
    if (nodes[p].u != -1)
    {
        if (tmp.u == -1)
            return tmp = nodes[p], r + 1;
        node curt = pushup(tmp, nodes[p]);
        if (curt.u != -1)
            return tmp = curt, r + 1;
    }
    if (l == r)
        return l;
    int ls = query(tmp, l, mid, lson);
    if (ls <= mid)
        return ls;
    else
        return query(tmp, mid + 1, r, rson);
}

#undef mid
#undef rson
#undef lson

int main()
{
    memset(head, -1, sizeof(head)), n = read();
    for (int i = 1; i <= n; i++)
        wi[i] = read(), bucket[wi[i]] = i;
    for (int i = 2; i <= n; i++)
        up[i] = read(), addpath(up[i], i);
    dfs(1);
    for (int i = 1; i < 20; i++)
        for (int j = 1; j + (1 << i) - 1 <= ptot; j++)
            st[i][j] = (dep[st[i - 1][j]] < dep[st[i - 1][j + (1 << (i - 1))]]) ? st[i - 1][j] : st[i - 1][j + (1 << (i - 1))];
    for (int i = 2; i <= ptot; i++)
        log2_[i] = (log2_[i >> 1] + 1);
    build(0, n - 1, 1), q = read();
    while (q--)
    {
        int opt = read(), u, v;
        if (opt == 1)
        {
            u = read(), v = read(), swap(bucket[wi[u]], bucket[wi[v]]), swap(wi[u], wi[v]);
            update(wi[u], 0, n - 1, 1), update(wi[v], 0, n - 1, 1);
        }
        else
        {
            node tmp = node{-1, -1};
            printf("%d\n", query(tmp, 0, n - 1, 1));
        }
    }
    return 0;
}

E – The Fair Nut and Rectangles

首先有性质:矩形不会互相包含。也就是意味着随着 \(x\) 增大,\(y\)是单调递减的。我们可以设计出一个很 SB 的方程:

\[ dp[i] = \max_{j \in [1, i)} \{ dp[j] + S_i – S_i \cap S_j – a_i \} \]

设计出来之后,发现 \(S_i \cap S_j\) 随着 \(j\) 的递增而增大,所以上斜率优化即可。

// CF1083E.cpp
#include <bits/stdc++.h>

using namespace std;

const int MAX_N = 1e6 + 200;
const double eps = 1e-10;

typedef pair<int, int> pii;
typedef long long ll;

int n, q[MAX_N];
ll gans, f[MAX_N];

struct node
{
    ll x, y, cost;
    bool operator<(const node &rhs) const { return y > rhs.y; }
} nodes[MAX_N];

double X(int i) { return nodes[i].x; }

double Y(int i) { return f[i]; }

double slope(int i, int j) { return fabs(X(j) - X(i)) < eps ? 1e10 : double(Y(j) - Y(i)) / double(X(j) - X(i)); }

int main()
{
    scanf("%d", &n);
    for (int i = 1; i <= n; i++)
        scanf("%lld%lld%lld", &nodes[i].x, &nodes[i].y, &nodes[i].cost);
    sort(nodes + 1, nodes + 1 + n);
    int head = 0, tail = 0;
    for (int i = 1; i <= n; i++)
    {
        while (head < tail && slope(q[head], q[head + 1]) >= nodes[i].y)
            head++;
        f[i] = 1LL * nodes[i].x * nodes[i].y - nodes[i].cost;
        if (head <= tail)
            f[i] = max(f[i], f[q[head]] + 1LL * (nodes[i].x - nodes[q[head]].x) * nodes[i].y - nodes[i].cost);
        gans = max(gans, f[i]);
        while (head < tail && slope(q[tail - 1], q[tail]) <= slope(q[tail], i))
            tail--;
        q[++tail] = i;
    }
    printf("%lld\n", gans);
    return 0;
}

 

Leave a Reply

Your email address will not be published. Required fields are marked *