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;   
}
posted @ 2021-05-30 10:33  shuitiangong  阅读(113)  评论(0编辑  收藏  举报