一、来源: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. 进程锁(互斥锁)(Python)

    3:# 抢票示例 import json import time from multiprocessing import Process,Lock def search(i): with open(' ...

  2. javascript按钮通过cookie限制60s后才可以点击

    javascript按钮通过cookie限制60s后才可以点击 1️⃣ 首先创建一个html页面,放入一个按钮 2️⃣ 设置点击按钮的触发函数 一般当点击按钮都会有一些业务需要,在需求结束后,触发sa ...

  3. SUM和IF使用求部分和

    GROUP BY可以按照某一列的不同值进行分组,然后将不同组的数据可以利用聚合函数进行汇总取值. --我们可以在老师表里面求解不同班级的老师分别有多少名 SELECT class_id,COUNT(t ...

  4. 详解 & 0xff 的意义及作用

    首先我们要都知道, &表示按位与,只有两个位同时为1,才能得到1, 0x代表16进制数,0xff表示的数二进制1111 1111 占一个字节.和其进行&操作的数,最低8位,不会发生变化 ...

  5. .NET Core开发实战(第3课:.NET Core的现状、未来以及环境搭建)--学习笔记

    03 | .NET Core的现状.未来以及环境搭建 .NET Core的现状 .NET Core 的应用场景:桌面端.Web端.云端.移动端.游戏.IOT 和 AI 云端指的是 .NET Core ...

  6. 高效发现和解决insert字段长度不够的报错

    早上发现执行的PostgreSQL 存储过程报错,错误如下: 300-value too long for type character varying(100),一看就是表字段的长度太小,从提示看是 ...

  7. Java控制语句

    1.介绍 从本质上讲,程序是一系列指令.控制结构是可以改变我们如何执行这些指令的代码块. 在本教程中,我们将探讨Java中的控制结构. 有三种控制结构: 条件分支,用于在两条或多条路径之间进行选择.J ...

  8. 如何基于three.js(webgl)引擎架构,实现3D密集架库房,3D档案室(3d机器人取档、机器人盘点、人工查档、设备巡检)

     前言: 这是最好的时代,也是最坏的时代:是充满挑战的时代,也是充满机遇的时代.是科技飞速的时代,也是无限可能的时代. 近年来,人工智能(AI)技术的飞速发展已经席卷了全球,不断突破着技术边界,为各行 ...

  9. centos7 搭建snmpv3靶场

    安装文件 yum install net-snmp net-snmp-utils -y 关闭服务创建用户 systemctl stop snmpd # 添加一个用户 如 root net-snmp-c ...

  10. 初级算法 - C++反转链表

    顾名思义, 就是将链表的所有结点反转. 解释见:[剑指offer]反转链表,C++实现(链表) 代码: #include <iostream> struct NodeList { int ...