Codeforces Round 1054 (Div. 3) - D、E

Codeforces Round 1054 (Div. 3)

D. A and B

参考了 Tutorial

题意很简单,(总结后)就是将所有的字符 a 或者所有的字符 b 汇集到一起。那么对于每种字符分别考虑位置聚到一起的代价,选择小的就是答案。

Let the target be to make all occurrences of one letter contiguous. Do it for both letters and take the minimum.
Fix a letter \(c\in{a,b}\) and let its positions be \(p_0<p_1<\dots<p_{m-1}\). If we place these \(m\) copies into a consecutive block starting at some index \(L\), the number of adjacent swaps needed is $ \sum_{i=0}^{m-1} \bigl|, p_i - (L+i) ,\bigr| ;=; \sum_{i=0}^{m-1} \bigl|, (p_i - i) - L ,\bigr|$
Set \(b_i=p_i-i\). The function \(\sum_i |b_i-L|\) is minimized when \(L\) is a median of \({b_i}\). Hence the optimal cost to cluster all \(c\)'s is
$ \operatorname{cost}(c) = \sum_{i=0}^{m-1} \bigl|, b_i - \operatorname{med}(b) ,\bigr|, \quad \text{where } b_i = p_i - i.$
The answer is \(\min(\operatorname{cost}(a),\operatorname{cost}(b))\).
This counts the minimal number of adjacent swaps because each swap reduces the sum of pairwise inversions between the two types by exactly \(1\), and aligning to a consecutive block achieves the minimum. The algorithm computes positions, builds \(b_i\), takes the median, and sums absolute deviations — all in linear time after positions are known.
The time complexity is \(O(n)\).

在代码实现中,最终计算的是 val += abs(v[pos] - v[i]) - abs(pos - i);。这样的写法和题解的描述是等价的!
中位数的选取即为 k = m / 2 位置上的数 p[k] - k
题解公式为 \(cost(a) = \sum_{i = 0}^{m - 1} |b_i - b_k| = \sum_{i = 0}^{m - 1} |(p_i - i) - (p_k - k)|\)
代码对应的公式为 \(val = \sum_{i = 0}^{m - 1} (|p_i - p_k| - |i - k|)\)
对于本题,这两个式子是对应成立的

代码:Qiansui_code

E. Hidden Knowledge of the Ancients

做法一:双指针法

对于每一个位置,考虑其作为左边界时,最小和最大的右边界的位置,利用两个双指针维护即可;在这些位置中统计区间长度满足在 l 和 r 之间的即可

void solve(){
    int n, k, l, r;
    cin >> n >> k >> l >> r;
    vector<int> a(n);
    for(int i = 0; i < n; ++ i) cin >> a[i];
    ll ans = 0;
    int j1 = -1, j2 = -1, cnt1 = 0, cnt2 = 0;
    map<int, int> mp1, mp2;
    for(int i = 0; i < n; ++ i){
        while(j1 < n && cnt1 < k){
            ++ j1;
            if(j1 >= n) break;
            ++ mp1[a[j1]];
            if(mp1[a[j1]] == 1) ++ cnt1;
        }
        while(j2 < n && cnt2 <= k){
            ++ j2;
            if(j2 >= n) break;
            ++ mp2[a[j2]];
            if(mp2[a[j2]] == 1) ++ cnt2;
        }
        ans += max(0, min(r, j2 - i) - max(l, j1 - i + 1) + 1);
        -- mp1[a[i]];
        if(mp1[a[i]] == 0) -- cnt1;
        -- mp2[a[i]];
        if(mp2[a[i]] == 0) -- cnt2;
    }
    cout << ans << "\n";
    return ;
}

做法二:容斥法
根据容斥原理:恰好 k 个的个数 = 最多 k 个的个数 - 最多 k - 1 个的个数

思路:考虑统计每个位置作为右边界时,有多少个区间满足最多 k 个的条件和最多 k - 1 个的条件,且均满足区间长度在 l 和 r 之间

void solve(){
    int n, k, l, r;
    cin >> n >> k >> l >> r;
    vector<int> a(n);
    for(int i = 0; i < n; ++ i) cin >> a[i];
    auto calc = [&](int mx) -> ll {
        int cnt = 0;
        map<int, int> mp;
        ll ans = 0;
        for(int x = 0, y = 0; y < n; ++ y){
            ++ mp[a[y]];
            if(mp[a[y]] == 1) ++ cnt;
            while(cnt > mx){
                -- mp[a[x]];
                if(mp[a[x]] == 0) -- cnt;
                ++ x;
            }
            ans += max(0, y - l + 1 - max(y - r + 1, x) + 1);
        }
        return ans;
    };
    cout << calc(k) - calc(k - 1) << '\n';
    return ;
}

参考链接

posted @ 2025-10-27 01:18  Qiansui  阅读(13)  评论(0)    收藏  举报