CF_2149_D. A and B
题目链接:Problem - D - Codeforces
题目大意:
长度为 的字符串 ,仅由字符 'a' 和 'b' 组成
每次操作,交换相邻的字符
求:最少的操作次数,使得同一种字符('a' 或 'b')全部连续地排列在一起,形成恰好一个连续的块
中位数:
只考虑字符 'a' ,要把字符串中所有的 全归于一段连续的区间
首先,我们选出一个起点 st,
贪心思想,最终排列的相对位置仍是开始时的相对位置 (总不可能开始时最后面的'a',最终跑到最前面的位置吧),
显然,对于每个字符 'a' ,操作次数 = 最终位置 - 开始位置
很明显在最终状态下,从左往右数第一个 'a' 的位置是 st ,第二个是 st + 1,第三个是 st + 2。。。。第 i 个是 st + i - 1
设每个字符 'a' 开始的位置为 pos[i]
对于第一个 'a' 的操作数是 | pos[1] - st |,第二个是 | pos[2] - st - 1 |,第三个是 | pos[3] - st - 2 |。。。。第 i 个是 | pos[i] - st - i + 1 |
即:操作次数 = ∑ | pos[i] - st - i + 1 | = ∑ | ( pos[i] - i + 1 ) - st |
把 ( pos[i] - i + 1 ) 看成 Xi
得到最终的式子:操作次数 = ∑ | Xi - st |
当 st 为 X 的中位数,式子的值最小
当a成连续块时,b也一定是连续块,
答案对 只考虑a 和 只考虑b 取最小值即可
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<vector>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<map>
#include<unordered_set>
#include<unordered_map>
#include<bitset>
#include<tuple>
#define inf 72340172838076673
#define int long long
#define endl '\n'
#define F first
#define S second
#define mst(a,x) memset(a,x,sizeof (a))
using namespace std;
typedef pair<int, int> pii;
const int N = 200086, mod = 998244353;
int n;
string s;
int cal(vector<int> q) {
int res = 0;
int mid = q[q.size() / 2];
for (auto x : q) res += abs(x - mid);
return res;
}
void solve() {
cin >> n >> s;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'a') cnt++;
else cnt--;
}
if (abs(cnt) == n) {
cout << 0 << endl;
return;
}
vector<int> pa, pb;
int la = 0, lb = 0;
for (int i = 0; i < n; i++) {
if (s[i] == 'a') pa.push_back(abs(i - la++));
else pb.push_back(abs(i - lb++));
}
cout << min(cal(pa), cal(pb)) << endl;
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T = 1;
cin >> T;
while (T--) solve();
return 0;
}

浙公网安备 33010602011771号