我吐了
这D题真的很水,难度和A题差不多(真的不夸张,很多人只是没看题把)
你要是没做出来,真的很不应该
把 快 乐 因 子 分 成 两 种 , 一 种 是 大 于 m 的 , 选 了 后 , 肯 定 闭 嘴 d 天 把快乐因子分成两种,一种是大于m的,选了后,肯定闭嘴d天 把快乐因子分成两种,一种是大于m的,选了后,肯定闭嘴d天
一 种 是 小 于 等 于 m 的 , 选 了 后 , 没 事 哦 一种是小于等于m的,选了后,没事哦 一种是小于等于m的,选了后,没事哦~
那 我 们 直 接 枚 举 选 几 个 快 乐 因 子 大 于 m 的 不 就 行 了 吗 ? 那我们直接枚举选几个快乐因子大于m的不就行了吗? 那我们直接枚举选几个快乐因子大于m的不就行了吗?
比 如 选 x 个 快 乐 因 子 大 于 m 的 , 那 我 肯 定 拿 x 个 快 乐 因 子 最 大 的 , 反 正 都 是 闭 嘴 比如选x个快乐因子大于m的,那我肯定拿x个快乐因子最大的,反正都是闭嘴 比如选x个快乐因子大于m的,那我肯定拿x个快乐因子最大的,反正都是闭嘴
其 中 有 一 个 快 乐 因 子 在 第 n 天 放 , 这 样 这 次 就 不 用 闭 嘴 了 , 只 需 要 消 耗 1 天 其中有一个快乐因子在第n天放,这样这次就不用闭嘴了,只需要消耗1天 其中有一个快乐因子在第n天放,这样这次就不用闭嘴了,只需要消耗1天
所 以 此 时 消 耗 了 ( x − 1 ) ∗ ( d + 1 ) + 1 所以此时消耗了(x-1)*(d+1)+1 所以此时消耗了(x−1)∗(d+1)+1
剩 下 的 几 天 , 都 选 快 乐 因 子 小 于 等 于 m 的 且 最 大 的 , 反 正 不 用 闭 嘴 了 嘛 剩下的几天,都选快乐因子小于等于m的且最大的,反正不用闭嘴了嘛 剩下的几天,都选快乐因子小于等于m的且最大的,反正不用闭嘴了嘛
#include
using namespace std;
#define int long long
int a[100009],b[100009],pre[100009];
int top1,top2,n,d,m;
bool com(int q,int w){
return q>w;
}
signed main()
{
cin >> n >> d >> m;
for(int i=1;i<=n;i++)
{
int x; scanf("%lld",&x);
if( x<=m ) a[++top1]=x;//不被禁言的
else b[++top2]=x;//要被禁言的
}
sort(a+1,a+1+top1,com);
sort(b+1,b+1+top2,com);
for(int i=1;i<=n;i++) pre[i]=pre[i-1]+a[i];
int sumn=0,ans=pre[n];
//我这里强调一点,评论区也有朋友指出了
//我们把其中一个大于m的放在n位置可以省掉这次的禁言时间
//所以选x个大于m的最少花费(n-1)*(d+1)+1天,记作q
//若最后一个不放在n,则最多可能禁言天数完全占满,最多花费n*d天,记作w
//下面计算剩余可用的天数实际上是一个区间,[n-w,n-q]
//若小于m的总天数不在这个区间范围,说明根本不能形成(填充)一个排列
//在这个区间范围,我们肯定选可利用天数最多的,也就是yu=n-q
for(int j=1;j<=top2;j++)//被禁言几次
{
sumn+=b[j];
int yu=(j-1)*(d+1)+1;
if( yu>n ) break;
yu=n-yu;//现在最多还可以选yu个不大于m的
ans=max(ans,sumn+pre[yu] );
}
cout << ans;
}