字符串大模拟

传送门

题意:

给定一个长度为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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值