题意:
给定一个长度为n的由小写字母构成的字符串s,现在如果有一个字符串t长度为2n,且t中有n个不同的字母,并且每个字母出现2次,则称字符串t为漂亮字符串。要求计算对s进行更改的最小次数,使得s变为一个漂亮字符串,同时与原字符串相比变化最小。
思路:
贪心,计算原字符串各个字母的种类个数sz 出现次数cnt_i,按照次数排序,因为只有26个字母,可以暴力枚举最小操作次数所带有的字符种类数目num。如果num < sz,那么取最大的前num个字符保留,操作次数为 op = abs(n / num - cnt_i) , 剩下的全部删除,操作次数加上 abs(n/num - cnt_i); 注意op要除以2,因为删除和更改计算了两次,其实更改一次就删除了一次。
得到最合适的字符种类数目num,就开始更改
#include <bits/stdc++.h>
#define oo 0x3f3f3f3f
#define ll long long
#define OO 0x3f3f3f3f3f3f3f3f
#define IO ios::sync_with_stdio(false);cin.tie(nullptr)
#define rep(i,a,n) for (ll i=a;i<=n;i++)
#define per(i,a,n) for (ll i=a;i>=n;i--)
#define int ll
const int N = 2e5 + 10, M = 2 * N;
using namespace std;
typedef pair<int, int> pii;
#define deb(i,x) if(int i==x) int k = 1;
#define all(x) x.begin(),x.end()
ll lowbit(ll x) { return x & -x; }
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
ll qmi(ll a, ll b, ll mod) {
ll res = 1; while (b) { if (b & 1) res = res * a % mod; a = a * a % mod; b >>= 1; }
return res;
}
signed main()
{
IO;
#ifndef ONLINE_JUDGE
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
int t; cin >> t;
while (t--)
{
int n; cin >> n;
string s; cin >> s;
vector<int> cnt(26), id(26);
for (int i = 0; i < n; i++)
cnt[s[i] - 'a']++;
for (int i = 0; i < 26; i++)
id[i] = i;
sort(id.begin(), id.end(), [&](int a, int b) {return cnt[a] > cnt[b]; });
int op = 1e9, num;
for (int i = 1; i <= 26; i++)
{
if (n % i == 0)
{
int d = n / i;
int sum = 0;
for (int j = 0; j < i; j++)
sum += abs(d - cnt[id[j]]);
for (int j = i; j < 26; j++)
sum += cnt[id[j]];
sum /= 2;
if (op > sum) {
op = sum;
num = i;
}
}
}
for (int i = 0; i < num; i++)
cnt[id[i]] -= n / num;//作差处理,大于零说明有的多,需要更改,
for (int i = 0, j = num - 1; i < n; i++)
{
while (j >= 0 && cnt[id[j]] >= 0)j--;
if (cnt[s[i] - 'a'] > 0)
{
cnt[s[i] - 'a']--;
s[i] = char('a' + id[j]);
cnt[id[j]]++;
}
}
cout << op << endl;
cout << s << endl;
}
return 0;
}