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 ;
}
参考链接
本文来自博客园,作者:Qiansui,转载请注明原文链接:https://www.cnblogs.com/Qiansui/p/19167696

浙公网安备 33010602011771号