CF1430E String Reversal
可以想到一个结论:(不会证)
在原字符串中的相同字符,经过操作后相对位置不变。
思路
我们可以给 'a'-'z' 每个字符开个数组,
它们各自在目标字符串中的出现位置存到一个“桶”里。
然后再把这个“桶”对应到原字符串里,就会得到一个数组。
比如说,aabcba 这个字符串,它的目标字符串就是 abcbaa。
存每个字母在目标字符串中的位置:
a: 1, 5, 6
b: 2, 4
c: 3
然后再把每个字母从“桶”里取出来,对应到原字符串 abcbaa 里
a: 1
a: 5
b: 2
c: 3
b: 4
a: 6
我们只需要计算,这个数组相邻交换几次可以变成排好序的 1-n。
也就是这个数组的逆序对(这里是三个,也就是交换三次)。
代码
#include <iostream>
#include <cstdio>
#include <string>
#include <cstring>
#include <utility>
#include <algorithm>
#define int long long
using namespace std;
int c[200050], rk[200050], vis[30], ap[30][200050], n, ans;string s, t;pair<int, int> a[200050];
int lbt(int x) {return x & -x;}
void chg(int x, int k)
{
for(int i = x;i <= n;i += lbt(i))
c[i] += k;
}
int ask(int x)
{
int ret = 0;
for(int i = x;i;i -= lbt(i))
ret += c[i];
return ret;
}
signed main()
{
cin >> n >> s;t = s;reverse(t.begin(), t.end());
n = s.length();s = ' ' + s;t = ' ' + t;
for(int i = 1;i <= n;++i)
ap[t[i] - 'a'][vis[t[i] - 'a']++] = i;
memset(vis, 0, sizeof vis);
for(int i = 1;i <= n;++i)
a[i].first = ap[s[i] - 'a'][vis[s[i] - 'a']++], a[i].second = i;
sort(a + 1, a + n + 1);
for(int i = 1;i <= n;++i)
rk[a[i].second] = i;
for(int i = n;i >= 1;--i)
{
chg(rk[i], 1);
ans += ask(rk[i] - 1);
}
cout << ans << endl;
return 0;
}

浙公网安备 33010602011771号