D. Boboniu Chats with Du (662 div2 贪心 枚举)

D. Boboniu Chats with Du

题意: 给 n 个快乐值,你可以按任何顺序在群里说出快乐值为 k i k_i ki 的话,当 m < k i mm<ki 时,你会获得 d 天的禁言(不包括当天),n 天后你的快乐值的和最大是多少。
思路: 很明显的贪心,但是不是太好想。
首先我们把大于 m 的与小于等于 m 的数分开存到 a 、 b a、b ab 数组中,然后分别从大到小排序。
所以如果我们说快乐值大于 m 的话,那么每次肯定说最大的 ai,当说 num 次 ai 时要耗费 t = ( n u m − 1 ) ∗ ( d + 1 ) + 1 t=(num-1)*(d+1)+1 t=(num1)(d+1)+1 的天数(第n天说最后一个大于m的话),那么还剩下 n − t n-t nt 天需要说不被禁言的话,那就从 bi 中挑前 n-t 大的来说。然后就枚举 num 找个最大的即可。

#include

using namespace std;
typedef long long LL;
const int N = 1e5+7;

int a[N];
LL h[N],s[N],cnt1,cnt2;

bool cmp(int x,int y){
	return x>y;
}

int main()
{
	int n,d,m,t;
	cin>>n>>d>>m;
	for(int i=1;i<=n;i++) {
		cin>>t;
		if(t>m) h[++cnt1] = t;
		else s[++cnt2] = t;
	}
	sort(h+1,h+1+cnt1,cmp);
	sort(s+1,s+1+cnt2,cmp);
	for(int i=1;i<=cnt1;i++) h[i] += h[i-1];
	for(int i=1;i<=n;i++) s[i] += s[i-1]; 	//注意这里的前缀和要长度为 n 
	
	LL ans = s[cnt2];  // 防止全小于等于 m
	for(int num=1;num<=cnt1;num++){  //枚举禁言次数 
		LL k = (LL)(num-1)*(d+1)+1;  //禁言num次时用多少天 
		if(k <= n) ans = max(ans,h[num]+s[n-k]);  //禁言当天的快乐值+剩余天数中不被禁言的快乐值 
	}
	cout<<ans<<endl;
	return 0;
}

你可能感兴趣的:(CF,贪心)