【洛谷 P8739】[蓝桥杯 2020 国 C] 重复字符串 题解(字符串+贪心算法)

[蓝桥杯 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 1K105 1 ≤ ∣ S ∣ ≤ 1 0 5 1 \le |S| \le 10^5 1S105。其中 ∣ 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 nm。将这个数量加到 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;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值