思路:
这题分两个步骤写,第一步将字符串分为两部分,然后把左右多余的放到右边去,把右边多余的放到左边来。这一步可以简化为把字符数小于等于该字符总数的1/2的放到pre 中,然后把 多余的放进ne中。
第二步就是把ne变成pre,这里用到了求逆序对的数量的个数的算法。我们按照pre中的顺序给ne标号,那么我们就把问题转化为了求ne中逆序对的数量,我们可以用树状数组 或者归并排序的方法来做,这里用了归并排序的思路。
AC code:
#include<bits/stdc++.h>
#define endl "\n"
#define pii pair<int,int>
#define ll long long
using namespace std;
const int N = 2e5 + 5;
int pos[N], sum[N];
int now[27];
int q[N],t[N];
ll ans = 0;
void merge_sort(int q[], int l, int r) // 归并排序模板
{
if (l >= r) return;
int mid = l + r >> 1;
merge_sort(q, l, mid);
merge_sort(q, mid + 1, r);
int i = l, j = mid + 1, k = 0;
while (i <= mid && j <= r)
{
if (q[i] <= q[j]) t[++k] = q[i++];
else
{
ans += ll(mid - i + 1);
t[++k] = q[j++];
}
}
while (i <= mid) t[++k] = q[i++];
while (j <= r) t[++k] = q[j++];
for (int i = l,j = 1; i <= r; i++,j++)
{
q[i] = t[j];
}
return;
}
int main()
{
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int n;
cin >> n;
string s;
cin >> s;
s = " " + s;
for (int i = 1; i <= n; i++)
{
sum[s[i] - 'a'] ++;
} // 记录各字符总个数
string pre, ne;
for (int i = 1; i <= n; i++)
{
int x = sum[s[i] - 'a'];
int y = now[s[i] - 'a'];
if (y < x / 2) // 表示pre中需要该字符,把该字符移到pre中并计算步骤
{
pre += s[i];
ans += i - pre.size();
}
else
ne += s[i];
now[s[i] - 'a']++;
}
// cout << ans << endl;
string tmp = pre;
// 第二步,先把ne 标号
for (int i = 0; i < n / 2; i++)
{
int ff = tmp.find(ne[i]);
tmp[ff] = '?';
q[i + 1] = ff+1; // 用q数组标号,然后对q进行归并排序 并求逆序对的数量
}
// for (int i = 1; i <= n / 2; i++) cout << q[i] << " ";
merge_sort(q, 1, n / 2);
cout << ans << endl;
return 0;
}