Codeforces 1526D - Kill Anton(逆序数)
题目大意
给你一个字符串s,让你用s中的字符构造t,使得t通过交换相邻的字符变成s的最小交换次数最大。
解题思路
结论是相同的字符都放一起结果不会更差(不会证)。然后因为只有4个字符,所以可以用全排列枚举所有方案,然后求逆序数。因为就只有4个字符,且都是相连的,所以可以先求出每个字符换到其他字符前面需要的交换次数,这样就能O(n)求逆序数了。
代码
const int maxn = 1e5+10;
map<char, int> mp = {{'A', 0}, {'O', 1}, {'T', 2}, {'N', 3}};
ll c[5][5], c2[5];
int main(void) {
IOS; int __; cin >> __;
while(__--) {
string a = "AOTN";
sort(a.begin(), a.end());
string s; cin >> s;
int n = s.size();
for (int i = 0; i<n; ++i) ++c2[mp[s[i]]];
for (int i = 0; i<4; ++i) {
int cnt = 0;
for (int j = 0; j<n; ++j) {
c[i][mp[s[j]]] += cnt;
if (i==mp[s[j]]) ++cnt;
}
}
ll maxx = 0; string ans = s;
do {
ll t = 0;
for (int i = 0; i<4; ++i)
for (int j = i+1; j<4; ++j) {
t += c[mp[a[j]]][mp[a[i]]];
}
if (t>maxx) {
maxx = t;
string tmp;
for (int i = 0; i<4; ++i)
for (int j = 0; j<c2[mp[a[i]]]; ++j)
tmp += a[i];
ans = tmp;
}
} while(next_permutation(a.begin(), a.end()));
cout << ans << endl;
clr(c, 0); clr(c2, 0);
}
return 0;
}