Featured image of post Codeforces Round #995(Div.3)

Codeforces Round #995(Div.3)

D

题目大意:给定一个整数序列 $a$,长度为 $n$,其中第 $i$ 个元素为 $a_i$。此外,还有两个整数 $x$ 和 $y$,且满足 $x \le y$。如果一对整数 $(i, j)$ 满足以下条件,则称其为有趣的: - $1 \le i < j \le n$; - 从序列 $a$ 中同时移除位置 $i$ 和 $j$ 的元素后,剩余元素的和在 $x$ 和 $y$ 之间。需要找出给定序列 $a$ 中有多少对这样的有趣整数组合。

数据范围:$1 \le t \le 10^4$,$3 \le n \le 2 \cdot 10^5$,$1 \le x \le y \le 2 \cdot 10^{14}$,$1 \le a_i \le 10^9$,$\sum n \le 2 \cdot 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
using i128 = __int128_t;
void solve() {
    ll n, x, y;
    cin >> n >> x >> y;
    vl a(n);
    rep(i, 0, n - 1) cin >> a[i];
    ranges::sort(a);
    ll tot = 0;
    rep(i, 0, n - 1) tot += a[i];
    ll ans = 0;
    rep(i, 0, n - 1) {
        ll tem = tot - a[i];
        int tem2 = lower_bound(a.begin(), a.begin() + i, tem - y) - a.begin();
        int tem3 = upper_bound(a.begin(), a.begin() + i, tem - x) - a.begin();
        ans += tem3 - tem2;
    }
    cout << ans << endl;
    return;
}

E

题目大意:伯兰德最大的商店收到了一批圣诞树,并已有 $n$ 位顾客前来欲购这些树。在销售启动前,商店需要统一为每棵树定价。为了合理制定价格,商店掌握了关于每位顾客的一些信息。对于第 $i$ 位顾客,有两个已知整数 $a_i$ 和 $b_i$,它们定义了顾客的购物行为: - 如果价格不超过 $a_i$,顾客将购买一棵树并给定正面评价; - 如果价格超过 $a_i$ 但不超过 $b_i$,顾客仍会购买,但会留下负面评价; - 如果价格高于 $b_i$,则顾客将不会购买。在负面评价不超过 $k$ 条的前提下,需要帮助商店计算出最大的可能收益。

数据范围:$1 \le t \le 10^4$,$1 \le n \le 2 \cdot 10^5$,$0 \le k \le n$,$1 \le a_i \le 2 \cdot 10^9$,$1 \le b_i \le 2 \cdot 10^9$,$a_i < b_i$,$\sum n \le 2 \cdot 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using i128 = __int128_t;
void solve() {
    ll n, k;
    cin >> n >> k;
    vl a(n), b(n);
    rep(i, 0, n - 1) cin >> a[i];
    rep(i, 0, n - 1) cin >> b[i];
    ranges::sort(a);
    ranges::sort(b);
    ll ans = 0;
    rep(i, 0, n - 1) {
        ll tem = a[i];
        ll tem2 = ranges::lower_bound(a, tem) - a.begin();
        ll tem3 = ranges::lower_bound(b, tem) - b.begin();
        if (tem2 - tem3 <= k) ans = max(ans, (n - tem3) * tem);
    }
    rep(i, 0, n - 1) {
        ll tem = b[i];
        ll tem2 = ranges::lower_bound(a, tem) - a.begin();
        ll tem3 = ranges::lower_bound(b, tem) - b.begin();
        if (tem2 - tem3 <= k) ans = max(ans, (n - tem3) * tem);
    }
    cout << ans << endl;
    return;
}

F

题目大意:考虑一副有 $n$ 张牌的情况。牌中的位置从上到下编号为 $1$ 到 $n$。小丑位于位置 $m$。$q$ 操作按顺序应用于牌组。在第 $i$ 次操作期间,您需要在位置 $a_i$ 处取出卡片并将其移动到牌堆的开头或末尾。您的任务是计算每次操作后小丑可以所处的不同位置的数量。

数据范围:$1 \le t \le 10^4$,$2 \le n \le 10^9$,$1 \le m \le n$,$1 \le q \le 2 \cdot 10^5$,$1 \le a_i \le n$,$\sum q \le 2 \cdot 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
using i128 = __int128_t;
void solve() {
    ll n, m, q;
    cin >> n >> m >> q;
    vl a(q);
    rep(i, 0, q - 1) cin >> a[i];
    vl res(q);
    vector<pll> tem;
    tem.emplace_back(m, m);
    rep(i, 0, q - 1) {
        vector<pll> ntem;
        for (auto& [x, y] : tem) {
            if (y < a[i])
                ntem.emplace_back(x, y + 1);
            else if (x > a[i])
                ntem.emplace_back(x - 1, y);
            else {
                ntem.emplace_back(1, 1);
                ntem.emplace_back(n, n);
                if (x < a[i]) ntem.emplace_back(x, a[i]);
                if (a[i] < y) ntem.emplace_back(a[i], y);
            }
        }
        sort(all(ntem), [&](const pll& x, const pll& y) { return x.first < y.first; });
        tem.clear();
        for (auto& [x, y] : ntem) {
            if (tem.empty() || x > tem.back().second)
                tem.emplace_back(x, y);
            else
                tem.back().second = max(tem.back().second, y);
        }
        ll ans = 0;
        for (auto& [x, y] : tem) ans += y - x + 1;
        res[i] = ans;
    }
    rep(i, 0, q - 1) cout << res[i] << ' ';
    cout << endl;
    return;
}

G

题目大意:设想一个游戏,场地是由 $1 \times 10^9$ 这样的方格组成的长条,每个方格用从 $1$ 到 $10^9$ 的编号表示。你要在这些方格中放置 $n$ 条蛇(编号为 $1$ 到 $n$)。起初,每条蛇仅占据一个方格,且每个方格不能被多条蛇同时占用。在完成初始放置之后,游戏正式开始。游戏会持续 $q$ 秒。在每一秒,有两种可能的事件: - 蛇 $s_i$ 变长:如果蛇 $s_i$ 占据了方格区间 $[l, r]$,它会向右扩展,变成占据区间 $[l, r+1]$; - 蛇 $s_i$ 缩短:如果蛇 $s_i$ 占据了方格区间 $[l, r]$,它会向左收缩,变成占据区间 $[l+1, r]$。每秒钟只会发生其中一种事件。

数据范围:$1 \le n \le 20$,$1 \le q \le 2 \cdot 10^5$。

思路:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using i128 = __int128_t;
void solve() {
    ll n, q, x;
    char c;
    cin >> n >> q;
    int mask = (1LL << n);
    vvl dp(mask, vl(n, LLONG_MAX / 3));
    vl add(n), sub(n);
    vl add2(n);
    vvl dis(n, vl(n, 1));
    rep(i, 0, q - 1) {
        cin >> x >> c;
        x--;
        if (c == '+') {
            add[x]++;
            add2[x] = max(add2[x], add[x]);
            rep(j, 0, n - 1) {
                if (j == x) continue;
                dis[x][j] = max(dis[x][j], add[x] - sub[j] + 1);
            }
        } else {
            sub[x]++;
        }
    }
    rep(i, 0, n - 1) dp[(1LL << i)][i] = 1;
    dp[0][0] = 0;
    rep(i, 1, mask - 1) {
        rep(j, 0, n - 1) {
            if (dp[i][j] == LLONG_MAX / 3) continue;
            if (!((i >> j) & 1)) continue;
            rep(v, 0, n - 1) {
                if (i >> v & 1) continue;
                dp[i | (1 << v)][v] = min(dp[i | (1 << v)][v], dp[i][j] + dis[j][v]);
            }
        }
    }
    ll ans = LLONG_MAX;
    rep(i, 0, n - 1) ans = min(ans, dp[mask - 1][i] + add2[i]);
    cout << ans << endl;
    return;
}