[蓝桥杯 2020 国 C] 重复字符串
题目描述
如果一个字符串
S
S
S 恰好可以由某个字符串重复
K
K
K 次得到,我们就称
S
S
S 是
K
K
K 次重复字符串。例如 abcabcabc
可以看作是 abc
重复
3
3
3 次得到,所以 abcabcabc
是
3
3
3 次重复字符串。
同理 aaaaaa
既是
2
2
2 次重复字符串、又是
3
3
3 次重复字符串和
6
6
6 次重复字符串。
现在给定一个字符串 S S S,请你计算最少要修改其中几个字符,可以使 S S S 变为一个 K K K 次字符串?
输入格式
输入第一行包含一个整数 K K K。
第二行包含一个只含小写字母的字符串 S S S。
输出格式
输出一个整数代表答案。如果 S S S 无法修改成 K K K 次重复字符串,输出 − 1 −1 −1。
样例 #1
样例输入 #1
2
aabbaa
样例输出 #1
2
提示
其中, 1 ≤ K ≤ 1 0 5 1 \le K \le 10^5 1≤K≤105, 1 ≤ ∣ S ∣ ≤ 1 0 5 1 \le |S| \le 10^5 1≤∣S∣≤105。其中 ∣ S ∣ ∣S∣ ∣S∣ 表示 S S S 的 长度。
蓝桥杯 2020 年国赛 C 组 G 题。
思路
贪心策略:在每个子字符串中,选择出现次数最多的字符作为重复字符,其他不同的字符都需要修改。这是因为出现次数最多的字符意味着需要修改的字符最少,从而总的修改次数也最少。
选择局部最优解以达到全局最优解。在每个子字符串中,都独立地采取这种策略,最后得到的总修改次数就是全局最优解。
首先从输入中读取整数 n n n和字符串 s s s。如果字符串长度不能被 n n n整除,那么就无法将其修改为 n n n次重复的字符串。检查字符串的长度是否能被 n n n整除,如果不能,输出 − 1 -1 −1并结束程序。
接下来,定义数组 c n t cnt cnt来统计每个字母出现的次数。计算字符串 s s s的长度并将其除以 n n n,得到每个子字符串的长度 s e g L e n segLen segLen。定义一个变量 s u m sum sum来记录需要修改的字符数量。
然后,遍历字符串 s s s中的每一个子字符串。对于每个子字符串,首先将数组 c n t cnt cnt中的所有元素初始化为 0 0 0。然后遍历每个字符,将其转换为数组下标(通过减去字符’a’),并在 c n t cnt cnt中对应的位置加 1 1 1。这样, c n t [ j ] cnt[j] cnt[j]就表示字母 j j j在当前子字符串中出现的次数。
接着,遍历数组 c n t cnt cnt,找出其中的最大值 m m m。 m m m表示当前子字符串中出现次数最多的字母的出现次数。那么,为了将当前子字符串修改为 n n n次重复的字符串,需要修改的字符数量就是 n − m n-m n−m。将这个数量加到 s u m sum sum上。
最后,输出 s u m sum sum,即需要修改的字符总数量。
AC代码
#include <algorithm>
#include <cmath>
#include <iostream>
#define AUTHOR "HEX9CF"
using namespace std;
using ll = long long;
const int N = 1e6 + 7;
const int INF = 0x3f3f3f3f;
const ll MOD = 1e9 + 7;
int n;
string s;
int cnt[30];
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> n >> s;
int len = s.length();
if (len % n) {
// 不能被n整除
cout << -1 << "\n";
return 0;
}
// 分段长度
int segLen = len / n;
ll sum = 0;
// 偏移量
for (int i = 0; i < segLen; i++) {
// 初始化
for (int j = 0; j < 26; j++) {
cnt[j] = 0;
}
// 检查每段
for (int j = 0; j * segLen + i < len; j++) {
int t = j * segLen + i;
// cout << t << " " << s[t] << endl;
cnt[s[t] - 'a']++;
}
int m = 0;
for (int j = 0; j < 26; j++) {
m = max(m, cnt[j]);
}
sum += n - m;
// cout << m << " " << n - m << endl << endl;
}
// cout << sum << endl;
cout << sum << "\n";
return 0;
}