Codeforces Round #844 (Div. 1 + Div. 2, based on VK Cup 2022 - Elimination Round)

《C. Equal Frequencies》

 

 这道题的题意为:一个字符串str上每个字母的数量都一样,为平衡字符串

现在给出一个字符串s,问最少改动多少使s变成平衡字符串,并写出该平衡字符串

  

  这道题我之前一直想要找出一些规律,根本没往暴力方面想,现在想一下  

 

  一个平衡字符串上可能有1~26个字母

  知道一个平衡字符串上有多少字母(这里假设为i个字母),就知道每个字母有多少个

  知道每个字母有多少个(这里假设为x个,x=n/i),我们就可以贪心地

  

  1.如果原来字符串s的字母数(num)>i 

    我们贪心地将字母数最大的i个字母保留,后面 num-i个字母都要变成前i个字母

    同时前i个字母,如果字母数 > x,则要将多出来的部分补到少了的地方

  2.如果原来字符串s的字母数(num)==i

    如果字母数 > x,则要将多出来的部分补到少了的地方

  3.如果原来字符串s的字母数(num)<i

    如果字母数 > x,则要将多出来的部分补到少了的地方

  

  上面的i我们可以从1~26枚举出了

  然后比较得到最少操作数,与对应的平衡字符串上有i个字母时,改动最少

  根据这两个信息我们可以对原字符串进行改动

#include <iostream>
#include <algorithm>
#include <cstring>
#include <vector>
using namespace std;
struct node
{
    int n = 0, c;
    bool operator<(const node &t) const
    {
        return n > t.n;
    }
};
void solve()
{
    int n;
    cin >> n;
    vector<node> a(26);
    string str;
    cin >> str;
    for (int i = 0; i < 26; i++)
        a[i].c = i;
    for (int i = 0; i < str.length(); i++)
    {
        int c = str[i] - 'a';
        a[c].n++, a[c].c = c;
    }
    sort(a.begin(), a.end());
    /*  for (int i = 0; i < a.size(); i++)
         cout << a[i].n << " ";
     cout << endl; */
    int ans = 1e9, cnt;
    for (int i = 1; i <= 26; i++)
    {
        int res = 0;
        if (n % i)
            continue;
        int x = n / i;
        // i>=原来字符串中字母个数的情况
        // 将字母个数>x的字母要变成<x的字母;
        for (int j = 0; j < i; j++)
            res += (a[j].n > x ? a[j].n - x : 0);
        // 原来字符串中字母个数的情况>i的情况
        // 只选择字母数排名前i的字母,排名大于i的字母全部变成需要的字母
        for (int j = i; j < 26; j++)
            res += (a[j].n > 0 ? a[j].n : 0);
        if (ans > res)
            ans = res, cnt = i;
    }
    // 开始改变字符串的阶段:
    // 在cnt==原来字符串字母个数时,我们只要改字母数
    // 在cnt>原来字符串字母个数时,我们还要引入新的字母
    // 在cnt<原来字符串字母个数时,我们要将按照字母数排序的前cnt个字母给保留下来
    // 将后面的字母都变成需要的字母
    vector<char> s(n);
    vector<pair<int, int>> pos(26);
    for (int i = 0; i < a.size(); i++)
    {
        int c = a[i].c;
        pos[c] = {a[i].n, i + 1};
        /* cout << char(c + 'a') << " " << a[i].n << " " << i + 1 << endl; */
    }
    int need = n / cnt;
    /*  cout << "need ans cnt: " << need << " " << cnt << endl; */
    for (int i = 0; i < str.length(); i++)
    {
        int c = str[i] - 'a';
        /*  cout << "!: " << char(c + 'a') << " " << pos[c].first << " " << pos[c].second << endl; */
        // 说明需要更换字母
        if (pos[c].first > need || pos[c].second > cnt)
        {
            /* cout << "@: " << i << " "
                 << "entry" << endl; */
            // 在26个字母中找合法的字母
            for (int j = 0; j < 26; j++)
                if (pos[j].first < need && pos[j].second <= cnt)
                {
                    s[i] = j + 'a';
                    /*  cout << "find: " << char(j + 'a') << " " << pos[j].first << " " << pos[j].second << endl; */
                    pos[j].first++;
                    break;
                }
            if (pos[c].first > need)
                pos[c].first--;
        }
        else
        {
            /*  cout << "@: " << i << " "
                  << "entry2" << endl; */
            s[i] = str[i];
            /* cout << s[i] << " " << str[i] << endl; */
        }
    }
    cout << ans << endl;
    for (int i = 0; i < s.size(); i++)
        cout << s[i];
    cout << endl;
}
int main()
{
    int t;
    cin >> t;
    while (t--)
        solve();
    return 0;
}

 

    

 

posted @ 2023-01-20 20:00  次林梦叶  阅读(45)  评论(0)    收藏  举报