D. Boboniu Chats with Du(Codeforces Round #664 (Div. 2) )

感受
怎 么 这 么 傻 逼 的 题 目 , 我 现 场 A 不 了 呢 ? 看 来 还 有 不 少 提 升 的 空 间 怎么这么傻逼的题目,我现场A不了呢?看来还有不少提升的空间 A
题意
简 单 来 说 , 给 你 n 天 , 每 一 天 都 有 一 个 f u n 值 , 如 果 该 值 大 于 m , 则 选 择 该 天 , 然 后 后 d 天 不 能 选 择 。 否 则 , 不 影 响 , 问 最 优 情 况 下 可 以 获 得 的 最 大 f u n 之 和 简单来说,给你n天,每一天都有一个fun值,如果该值大于m,\\则选择该天,然后后d天不能选择。否则,不影响,问最优情况下\\可以获得的最大fun之和 nfunmdfun
思路
贪 心 想 , 然 后 会 发 现 一 个 很 牛 逼 的 性 质 。 现 场 打 的 时 候 就 像 个 智 障 , 不 知 道 使 用 , 硬 生 生 在 哪 里 贪 心 写 。 贪心想,然后会发现一个很牛逼的性质。现场打的时候就像个智障\\,不知道使用,硬生生在哪里贪心写。 使
转 入 正 题 : 转入正题:
我 们 考 虑 一 个 最 简 单 的 贪 心 , 那 就 是 a i < = m ( 集 合 S ) 的 能 选 就 选 , 对 于 > m ( 集 合 T ) 的 则 需 要 另 外 考 虑 。 我们考虑一个最简单的贪心,\\那就是a_i<=m(集合S)的能选就选,\\对于>m(集合T)的则需要另外考虑。 ai<=mS>mT
怎 么 考 虑 呢 ? 很 贪 心 地 想 , 就 是 利 用 S 中 的 较 小 元 素 进 行 换 , 有 没 有 发 现 一 个 性 质 : S ( 元 素 升 序 ) , T ( 元 素 升 序 ) , 最 优 答 案 一 定 是 选 择 S 的 某 一 个 后 缀 , 然 后 再 贪 心 选 择 T 的 某 个 后 缀 。 怎么考虑呢?很贪心地想,就是利用S中的较小元素进行\\换,有没有发现一个性质:\\S(元素升序),T(元素升序),最优答案一定是选择S的\\某一个后缀,然后再贪心选择T的某个后缀。 S:ST()ST
这 样 , 这 个 问 题 不 就 S o − E a s y 了 吗 ? 枚 举 S 的 后 缀 ( 可 以 为 空 ) , 然 后 贪 心 选 择 T 的 后 缀 , 怎 么 选 呢 ? 举 个 栗 子 , 如 果 我 们 选 择 S 的 后 缀 长 度 为 i , 那 么 也 就 是 说 ∣ S ∣ − i 个 天 数 会 被 剩 余 , 那 问 题 就 转 化 为 ∣ S ∣ − i + ∣ T ∣ 中 , 尽 可 能 在 T 中 选 最 大 后 缀 这样,这个问题不就So-Easy了吗?\\枚举S的后缀(可以为空),然后贪心选择T的后缀,怎么选呢?\\举个栗子,如果我们选择S的后缀长度为i,那么也就是说|S|-i个天数会被剩余,那问题就转化为|S|-i+|T|中,尽可能\\在T中选最大后缀 SoEasyS()TSiSiSi+TT

详 情 可 以 参 考 代 码 , 很 简 单 的 , 一 下 就 看 懂 了 ! 详情可以参考代码,很简单的,一下就看懂了!

#include <bits/stdc++.h>

using namespace std;
typedef long long ll;
const int maxn = 1e5 + 10;
ll sum[maxn], a[maxn];
int n, d, pos; ll m;
ll solve(int res){
	res = res + n - pos;
	int cnt = res / (d + 1); if(res % (d + 1)) cnt++;
	cnt = min(cnt, n - pos);
	int l, r; r = n; l = n - cnt + 1;
	return sum[r] - sum[l - 1];
}
void print(){
	puts("*********************");
	for(int i = 1; i <= pos; i++){
		printf("%lld ", a[i]);
	}
	putchar('\n');
	for(int i = pos + 1; i <= n; i++){
		printf("%lld ", a[i]);
	}
	putchar('\n');
	puts("*********************");
}
int main(){
	scanf("%d%d%lld", &n, &d, &m);
	for(int i = 1; i <= n; i++){
		scanf("%lld", &a[i]);
	}
	sort(a + 1, a + n + 1); pos = upper_bound(a + 1, a + n + 1, m) - a; pos--;
	for(int i = 1; i <= n; i++){
		sum[i] = sum[i - 1] + a[i];
	}
	ll ans = 0, tmp;
	for(int i = 1; i <= pos + 1; i++){
		tmp = sum[pos] - sum[i - 1];
		tmp += solve(i - 1);
		ans = max(ans, tmp);
	}
	printf("%lld\n", ans);
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值