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