2022年第十四届四川省大学生程序设计大赛 A

发布时间 2023-05-24 17:03:53作者: 清初

A Adjacent Swapping
题意:

给定一个字符串,每次可以移动相邻字符,求最小移动次数可以把它变成s+s这样左右两边相同的字符串。

思路:
1:我们知道他一定是偶数长度,所以我们把字符串分成两部分s1和s2

2:贪心的扫描一遍这个字符串,s1就是前一半,然后计算在满足这一般的时候他要移动多少次,即直接往前移动就可以了

len = i-s1.size()

3:此时的s2就是剩下的数组,我们需要把s2变成s1,所以也就是求s2变成s1需要多少步,求步数这个思想类似于冒泡排序

4:我们根据冒泡排序的性质:对于任意两个数看他是否逆序即大数在前小数在后如果逆序则进行交换次数+1,那么我们就可以根据这个性质求出s2到s1通过树状数组或归并排序求逆序对求出步数

点击查看代码
#include <bits/stdc++.h>

using namespace std;
#define int long long
map<char,int>mp;
queue<int>q[30];
const int N = 1e6 + 10;
int d[N];
int lowbit(int x)
{
    return x&(-x);
}
void add(int x)
{
    for(;x<= N;x += lowbit(x))
        d[x]++;
}
int query(int x)
{
    int res = 0;
    for(;x;x-=lowbit(x))
        res += d[x];
    return res;
}
void solve()
{
    int n;
    cin >> n;
    string s;
    cin >> s;
    for(int i = 0;i < n;i ++)
    {
        mp[s[i]] ++;
    }
    
    for(auto [l,r]:mp)
    {
        mp[l] = r/2;
    }
    
    string s1,s2;
    int ans = 0;
    for(int i = 0;i < n;i ++)
    {
        if(mp[s[i]]!=0)
            s2+=s[i],mp[s[i]]--,ans += i+1-s2.size();
        else
            s1 += s[i];
    }
    for(int i = 0;i < s2.size();i ++)
    {
        q[s2[i]-'a'].push(i);
    }
    vector<int>num;
    for(int i = 0;i < s1.size();i ++)
    {
        num.push_back(q[s1[i]-'a'].front());
        q[s1[i]-'a'].pop();
    }
    for(int i = 0;i < num.size();i ++)
    {
        ans += query(n/2)-query(num[i]+1);
        add(num[i]+1);
    }
    cout << ans << '\n';
}
signed main()
{
    solve();
}