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;
}

浙公网安备 33010602011771号