一、来源:Problem - C - Codeforces

二、题面

三、思路

  1. 先考虑一个子问题模型:我们现在有用\(m_1\)种随机字母组成的n个数,各字母个数未定,现在需要使这n个数变为\(m_2\)种类,平均每个种类为blance=n/\(m_2\)个数,问如何求得最小的改变数

    • 显然,只能由多的数向少的数改变,为此我们先尝试求出所有所有字母出现的次数并对其进行降序排序得到vector<pair<int,int>> v;\\pair的first为字母小标(由0开始),second为字母出现的个数

    • 我们考虑转换的过程,其实就是高位-1,低位+1的过程.

      • 尝试只找需要减去的位,初一看我们在前面高位用v[i].second减去blance直到v[i].second<=blance即可,然而事实上这情况讨论过的前提是\(m_1<m_2\);当\(m_1>m_2\),以数列9,3,3,3,2为例,我么将其转为为5,5,5,5,,最前面的9需要减去,后面的2也需要减去,这就比较复杂了
      • 尝试只找需要增加的位:根据上面错误的经验,我们可以得到需要增加的部分都是在m2之前的,且都可以使用表达式ans+=blance-v[i].second.经代码验证可以得到复合题意的解
    • code

      #include<bits/stdc++.h>
      
      using namespace std;
      
      bool cmp(const pair<int,int> a,pair<int,int> b){
      return a.second > b.second;
      } char toChar(int offset){
      return 'a'+offset;
      } int toInt(char c){
      return c-'a';
      } int main(){
      int t;
      cin >> t;
      while(t--){
      int n,m2; //n个数转换为m种,每种n/m个
      char str[100];
      cin >> n >> m2;
      cin >> str;
      map<int,int> mp;
      for(int i=0;i<26;i++){ //需初始化
      mp[i]=0;
      }
      int m1=0;
      for(int i=0;i<n;i++){
      if(++mp[toInt(str[i])]==1){
      m1++;
      }
      }
      vector<pair<int,int>> v(mp.begin(),mp.end());
      sort(v.begin(),v.end(),cmp);
      int ans=0,blance=n/m2;
      for(int i=0;i<m2;i++){
      if(v[i].second<blance){
      ans+=blance-v[i].second;
      }
      }
      cout << ans << endl;
      }
      return 0;
      }

    注:该问题模型其实还可以简化为:n个和为sum的数,每次加一减一,通过加减操作转化为m个相同的数,每个数为sum/m,所需要的最少加减次数

  2. 将问题分解:本题注意到小写字母是可以遍历的,我们可以遍历26种可能的情况求得变化最小的一次解的值,然后再对字符串进行变换

    • 遍历26种可能并求得变化最小的一个解
    • 模拟求变换即可(这里的代码属于是暴力了)
  3. 补充:对于toChar,toInt,最好还是封装为函数

四、代码

#include <bits/stdc++.h>
#define eleType int
#define INF 0x3f3f3f3f typedef long long ll; using namespace std; //字母遍历
//设字母总数为n,平等值为m => n<26*m且n%m==0 const int N=1e5+10;
char arr[N];
map<int,int> mp; bool cmp(const pair<int,int> a,pair<int,int> b){
return a.second > b.second;
} char toChar(int offset){
return 'a'+offset;
} int toInt(char c){
return c-'a';
} int main(){
int t;
cin >> t;
while(t--){
eleType n;
cin >> n >> arr;
for(int i=0;i<26;i++){ //需初始化
mp[i]=0;
}
int m1=0;
for(int i=0;i<n;i++){
if(mp[toInt(arr[i])]++==0){
m1++;
}
}
vector<pair<int,int>> v(mp.begin(),mp.end());
sort(v.begin(),v.end(),cmp);
eleType ans=INF,m2=1,blance;
for(int i=1;i<=26;i++){
if(n%i==0){ //i是种类,不是个数,不需要保证26*i>=n
// cout << "i:" << i << endl;
eleType temp=0,now=0;
blance=n/i;
for(int j=0;j<i;j++){
//cout << "mp[" << j << "]:" << mp[j] << endl;
if(v[j].second<blance){
temp+=blance-v[j].second;
}
}
// cout << temp << endl;
if(temp<ans){
ans=temp;
m2=i;
}
// cout << "i:" << i << " temp:" << temp << endl;
}
}
blance = n/m2;
eleType next=0;
for(int i=0;i<v.size();i++){
if(v[i].second<blance){
next=i;
break;
}
}
// cout << m2 << endl;
for(int i=0;i<n;i++){
eleType now;
for(int j=0;j<v.size();j++){
if(arr[i] == toChar(v[j].first)){ //易错漏,转换应封装为函数
now=j; //排序后的位置
}
}
if(v[now].second>blance||now>=m2){ //多余数,后者所在的种类位次超过m2
//在前面或后面
v[now].second--;
// cout << "v[next].first:" << v[next].first << endl;
arr[i]=toChar(v[next].first);
if(++v[next].second==blance){
next++;
} }
}
cout << ans << endl;
cout << arr << endl;
}
return 0;
}

Codeforces Round #844:C. Equal Frequencies的更多相关文章

  1. Codeforces Round #844 (Div.1 + Div.2) CF 1782 A~F 题解

    点我看题 A. Parallel Projection 我们其实是要在这个矩形的边界上找一个点(x,y),使得(a,b)到(x,y)的曼哈顿距离和(f,g)到(x,y)的曼哈顿距离之和最小,求出最小值 ...

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

    比赛链接 A 题意 设计一条线路要贴着6个墙面走,从 \((a,b)\) 到 \((f,g)\) ,线路长度最短. 题解 知识点:模拟. 分类取最短即可. 时间复杂度 \(O(1)\) 空间复杂度 \ ...

  3. cf之路,1,Codeforces Round #345 (Div. 2)

     cf之路,1,Codeforces Round #345 (Div. 2) ps:昨天第一次参加cf比赛,比赛之前为了熟悉下cf比赛题目的难度.所以做了round#345连试试水的深浅.....   ...

  4. Codeforces Round #262 (Div. 2) 1003

    Codeforces Round #262 (Div. 2) 1003 C. Present time limit per test 2 seconds memory limit per test 2 ...

  5. Codeforces Round #284 (Div. 2)A B C 模拟 数学

    A. Watching a movie time limit per test 1 second memory limit per test 256 megabytes input standard ...

  6. Codeforces Round #270 1003

    Codeforces Round #270 1003 C. Design Tutorial: Make It Nondeterministic time limit per test 2 second ...

  7. Codeforces Round #270 1002

    Codeforces Round #270 1002 B. Design Tutorial: Learn from Life time limit per test 1 second memory l ...

  8. Codeforces Round #285 (Div. 2) A B C 模拟 stl 拓扑排序

    A. Contest time limit per test 1 second memory limit per test 256 megabytes input standard input out ...

  9. Codeforces Round #367 (Div. 2) D. Vasiliy's Multiset (0/1-Trie树)

    Vasiliy's Multiset 题目链接: http://codeforces.com/contest/706/problem/D Description Author has gone out ...

  10. Codeforces Round #367 (Div. 2) C. Hard problem(DP)

    Hard problem 题目链接: http://codeforces.com/contest/706/problem/C Description Vasiliy is fond of solvin ...

随机推荐

  1. Mybatis(一对一、一对多、多对多)操作

    * 首先列出示例中用到的数据库表 user表: accout表: role表: user_role表: 建表语句如下: DROP TABLE IF EXISTS `user`; CREATE TABL ...

  2. VB6各类源码开源 - 开源研究系列文章

    今天把以前下载整理的关于VB6的一些代码进行了开源,覆盖了多个分类内容,需要的朋友请下载: VB6源码.part1 https://download.csdn.net/download/lzhdim/ ...

  3. TfrxReport.Clear。尽量慎用。

    for MyXuHaoKey in MyXuHaoJianRongSanJieKouDataDicApi.KeySortList do begin //标记下打印编号,吸入淘打的客户 MyTradeA ...

  4. 从零开始的react入门教程(三),了解react事件与使用注意项

    壹 ❀ 引 在从零开始的react入门教程(二),从react组件说到props/state的联系与区别一文中,我们介绍了react组件的基本用法以及props与state的区别.其中react组件分 ...

  5. NC14291 Cut

    题目链接 题目 题目描述 给你一个长度为 \(n\) 的序列,你每次可以将一个序列分割成两个连续的的子序列, 分割的代价为原序列的总和. 现在允许你在初始时将序列重新排列一次. 问分割成 \(n\) ...

  6. Linux下磁盘管理工具:hdparm/iostat/parted/fdiisk/badblocks/smartctl/losetup/sg3_utils/sqinfo/smp_utils/udevadm

    一.hdparm:       hdparm可以检测,显示与设定IDE,SCSI,SATA,SAS硬盘的硬件参数,       如: hdparm -I /dev/sdc 可以获取sdc的硬件信息  ...

  7. Spring Boot图书管理系统项目实战-11.检索图书

    导航: pre:10.借还统计 next: 只挑重点的讲,具体的请看项目源码. 1.项目源码 需要源码的朋友,请捐赠任意金额后留下邮箱发送:) 2.页面设计 2.1 index.html <!D ...

  8. win32- 函数运行速度测试

    LARGE_INTEGER nFreq, t1, t2; int loop_count = 0; double dt; double time_sum = 0; QueryPerformanceFre ...

  9. KPTP 汇报模板

    1.什么是KPTP 它是由4个单词:Keep.Problem.Try.Plan的首字母组成的. K:keep,今天做了哪些工作: P:problem,遇到了哪些问题: T:try,计划尝试如何解决这些 ...

  10. unrar命令

    解压提取RAR压缩文件 语法格式:unrar 参数 压缩包 常用参数 e 将文件解压缩到当前目录 o - 不要覆盖现有文件 l 显示文件列表 p 设置压缩包密码 p 将文件显示到标准输出 r 递归处理 ...