题目来源:P8739 [蓝桥杯 2020 国 C] 重复字符串 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
这道题一看就是贪心算法,但是我没能看出如何贪心,贪心的地方在哪,故写了这篇博客警示自己。言归正传:
题意描述:给定一段字符串s,在给定一个整数n,判断这个字符串是否可以转化成n次字符串,若能则输出修改字符串s的次数,不能则输出-1。
分析:我们需要先判断字符串可以分解为几段子序列(l=s的长度/n),当s的长度不能整除n时,直接输出-1,若整除则遍历字符串s的一段子序列(由于题目要求所有子序列相同,所以就直接取第一段子序列),然后在里面另开一重循环,循环的变量每次都加上l,用一个数组v来统计字符串中各个字符出现的频率(既然要修改字符,那么我们就先找出字符串s中出现频率最大的字符,将其他字符都修改为这个字符),找出出现频率最大的字符,每次循环都加上n-出现频率最大的字符的个数(将不同于这个字符的其他字符都转化为这个字符),最后输出结果。
代码如下:
#include<bits/stdc++.h>
#define int long long
#define endl "\n"
using namespace std;
int v[26];//桶的思维
int ans;
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
int n;
string s;
cin >> n >> s ;
int l=s.size()/n;//取第一段子序列长度
if(s.size()%n!=0) cout << "-1" << endl;//当不被整除时则不能拆分为n次字符串
else{
for(int i=0;i<l;++i){//外层循环只需遍历一次子序列即可
memset(v,0,sizeof v);
int maxn=0;
for(int j=i;j<s.size();j+=l){//内层循环的循环遍量每次加上l,每隔l个长度,将字符放入桶中
v[s[j]-'a']++;
}
for(int i=0;i<26;++i) maxn=max(maxn,v[i]);//找出单个字符出现最高的频率
ans+=n-maxn;//当都是这个字符时,那n-maxn都为0,则不需要变动,反之则加上需要变动的次数
}
cout << ans << endl;
}
return 0;
}