题目链接:
https://codeforces.com/problemset/problem/1430/E
题目大意:
给你一个长度为n的字符串,你可以执行一次操作使得
对其相邻两个字符进行交换你可以对其相邻两个字符进行交换
现在要求你给定的字符串变成其镜像的字符串最小需要多少次操作
如(aabb -> bbaa abc -> cba)
输入与输出:
input:
第一行一个n代表字符串长度
随后跟着一个长度为n的字符串(2 <= n <= 200000)
output:
一个数代表最小需要操作数
思路:
首先我们可以把源字符串的镜像字符串列出来,
那么这道题就变成了仅交换相邻元素由序列A到序列B的最小交换次数的问题
这种问题可以转化为两个序列间的索引的逆序对个数的问题
逆序对我们可以用树状数组做。
代码:
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 2e5 + 5;
char ch[maxn];
int len, xx[maxn];
queue<int> que[26];
typedef long long LL;
inline int getReverse(int ii)
{
return len + 1 - ii;
}
LL treeRes()
{
static int tree[maxn];
struct fun
{
inline static int lowbit(int ii) {
return ii & -ii;
}
inline static void update(int* tree, int ii, int xx) {
while (ii) {
tree[ii] += xx;
ii -= lowbit(ii);
}
}
inline static int read(int *tree, int ii) {
int res = 0;
while (ii < maxn) {
res += tree[ii];
ii += lowbit(ii);
}
return res;
}
};
LL res = 0;
for (int i = 1; i <= len; i++) {
int tres = fun::read(tree, xx[i] + 1);
res += tres;
fun::update(tree, xx[i], 1);
}
return res;
}
int main()
{
scanf("%d%s", &len, ch + 1);
for (int i = len; i >= 1; i--)
que[ch[i] - 'a'].push(i);
for (int i = 1; i <= len; i++) {
int ii = que[ch[i] - 'a'].front();
xx[i] = getReverse(ii);
que[ch[i] - 'a'].pop();
}
printf("%lld\n", treeRes());
}