Codeforces Round #723 (Div. 2) D. Kill Anton(树状数组)
Description
给出一个字符串 s,每次可以交换两个相邻的字符,要构造一个合法的字符串 t,使得 t 变为 s 所需要的操作次数最多
Input
4
ANTON
NAAN
AAAAAA
OAANTTON
Output
NNOTA
AANN
AAAAAA
TNNTAOOA
Solution
前置结论,操作次数最多的时候一定是相同的字母连接在一起的时候,比如: AAANNNOOTTT
至于结论的正确性,我想这应该是逆序对的特性;
有了结论之后,接下来只要枚举 ANOT,ANTO....等 24 种组合找到逆序对最多的字符串就可以了;
Code
const int N = 1e5 + 5;
ll n, m, _;
int i, j, k;
int a[N];
string t = "ANOT";
int bit[4];
int c[N], b[N];
map<char, vector<int>> mp;
void clear()
{
mp.clear();
bit[0] = bit[1] = bit[2] = bit[3] =0;
rep(i, 0, n) c[i] = 0;
t = "ANOT";
}
void add(int x)
{
for(; x <= n; x += lowbit(x)){
c[x] ++;
}
}
int ask(int x)
{
int ans = 0;
for(; x; x -= lowbit(x)){
ans += c[x];
}
return ans;
}
int idx(char ch)
{
if(ch == 'A') return 0;
if(ch == 'N') return 1;
if(ch == 'O') return 2;
if(ch == 'T') return 3;
}
string work(string s)
{
string ans = "";
rep(i, 0, 3){
int x = idx(t[i]);
rep(j, 1, bit[x]) ans += t[i];
}
return ans;
}
void init(string s)
{
for(int i = 0; s[i]; i ++){
mp[s[i]].pb(i + 1);
}
rep(i, 0, n) c[i] = 0;
}
ll go(string s)
{
int sz = s.size();
for(int i = sz - 1; i >= 0; i--){
b[i + 1] = *mp[s[i]].rbegin();
mp[s[i]].pop_back();
//dbg(b[i + 1]);
}
ll ans = 0;
per(i, 1, sz){
ans += ask(b[i]);
add(b[i]);
}
return ans;
}
signed main()
{
IOS;
rush(){
string str, s, ans;
cin >> str;
n = str.size();
for(int i = 0; str[i]; i++){
int x = idx(str[i]);
bit[x] ++;
}
ll maxx = 0;
do{
init(str);
s = work(str);
ll tmp = go(s);
if(tmp >= maxx){
maxx = tmp;
ans = s;
}
}while(next_permutation(t.begin(), t.end()));
ps(ans.c_str());
clear();
}
return 0;
}

浙公网安备 33010602011771号