CF624B 题解

CF624B 题解

题意

现在有 \(n\) 个字母,第 \(i\) 个字母最多用有 \(a_i\) 次,要将这些字母拼成一个尽可能长的字符串,但是每个字母出现的次数不能相等,求这个字符串长度的最大值。

思路

思路其实挺简单的:现将数组排序一下,这样个数一样的字母就排在一起了,接下来就设一个临时变量 \(cnt\),然后从字母个数大的开始加,这样就可以防止出现重复,这里 \(cnt\) 就有大作用了:统计第 \(i\) 个字母实际用几次,由题意就有下面两种情况:

  1. \(cnt\geqslant a[i]\),这样说明第 \(i\) 个字母用的次数与其他已经遍历过的都不一样,(因为我们是从有的字母数大的开始遍历的)此时,将 \(cnt\) 赋值成 \(a[i]\) 就行了。
  2. \(0<cnt<a[i]\),这就说明第 \(i\) 个字母与前面遍历过的字母重复了,所以此时只需要将 \(cnt\) 减一。

最优只要将答案 \(ans\) 加上 \(cnt\) 就行了。

总结

  1. 开 long long,不开 long long 见祖宗。
  2. 分类讨论。
  3. 排序。
  4. 特殊初始化。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>//快排要用
using namespace std;
long long n,ans,a[105],cnt;//不开long long见祖宗
int main(){
	scanf("%lld",&n);
	for(int i=1; i<=n; i++) scanf("%lld",&a[i]);
	sort(a+1,a+1+n);//排序一下,这样用的次数一样的字母就在一起了。
	cnt=a[n]+1;//初始化,因为第一个要特殊加一。
	for(int i=n; i>=1; i--){
		if(cnt>a[i]) cnt=a[i];//如果cnt比a[i]大,则cnt=a[i]
		//这里就体现了为啥一开始要特殊加一
		else if(cnt) cnt--;//如果是正的,就减一。
		ans+=cnt;//加一下。
	} 
	printf("%lld",ans); 
	return 0;
}
posted @ 2025-01-29 15:33  naroto2022  阅读(19)  评论(0)    收藏  举报