解题思路
这是一道贪心算法题目,主要思路如下:
-
统计每个字母出现的次数:
- 使用长度为26的数组记录每个大写字母的出现次数
-
对字母出现次数进行排序:
- 从大到小排序,这样可以优先选择出现次数最多的字母
-
贪心选择:
- 从出现次数最多的字母开始选择
- 如果剩余可选数量m大于等于当前字母出现次数,全部选择
- 否则只选择m个,然后结束
-
计算得分:
- 每组相同字母的得分为:选择数量的平方
- 累加所有选择的得分
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
long long n, m;
while(cin >> n >> m) {
string str;
cin >> str;
// 统计字母出现次数
vector<long long> count(26, 0);
for(int i = 0; i < n; i++) {
count[str[i] - 'A']++;
}
// 排序
sort(count.begin(), count.end());
// 贪心选择
long long ans = 0;
int k = 25; // 从最大的开始
while(m > 0) {
if(m >= count[k]) {
// 可以全部选择
ans += count[k] * count[k];
m -= count[k];
k--;
} else {
// 只能选择部分
ans += m * m;
break;
}
}
cout << ans << endl;
}
return 0;
}
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNext()) {
long n = sc.nextLong();
long m = sc.nextLong();
String str = sc.next();
// 统计字母出现次数
long[] count = new long[26];
for(int i = 0; i < n; i++) {
count[str.charAt(i) - 'A']++;
}
// 排序
Arrays.sort(count);
// 贪心选择
long ans = 0;
int k = 25; // 从最大的开始
while(m > 0) {
if(m >= count[k]) {
// 可以全部选择
ans += count[k] * count[k];
m -= count[k];
k--;
} else {
// 只能选择部分
ans += m * m;
break;
}
}
System.out.println(ans);
}
}
}
def calculate_score(n, m, cards):
# 统计字母出现次数
count = [0] * 26
for c in cards:
count[ord(c) - ord('A')] += 1
# 排序
count.sort()
# 贪心选择
ans = 0
k = 25 # 从最大的开始
while m > 0:
if m >= count[k]:
# 可以全部选择
ans += count[k] * count[k]
m -= count[k]
k -= 1
else:
# 只能选择部分
ans += m * m
break
return ans
def main():
while True:
try:
n, m = map(int, input().split())
cards = input()
print(calculate_score(n, m, cards))
except EOFError:
break
if __name__ == "__main__":
main()
算法及复杂度
- 算法:贪心算法
- 时间复杂度:
- 其中
为字符串长度,
为字母表大小
- 空间复杂度:
- 需要一个数组存储字母出现次数