【香蕉OI】 假期生活 【codeforces 300iq contest 1 D】 Dates (贪心)

文章目录

题意

来自 租酥雨

在接下来的 t t t 天时间里,有 n n n 个女孩子想要和 xxx 约会。第 i i i 个女孩子想要在 [ l i , r i ] [li,ri] [li,ri] 中的某一天和 xxx 约会,且约会后 xxx 会得到 p i p_i pi 的偷税值。在这里,我们保证 l i ≤ l i + 1 , r i ≤ r i + 1 li≤li+1,ri≤ri+1 lili+1,riri+1 。xxx 在第 i i i 天至多和 a i a_i ai 个女孩子约会,他希望你能帮他求出他能够获得的最大偷税值之和。

思路

正解需要用到霍尔定理,但是 tiandong123 并不需要这么麻烦,他只需要一个 multiset (喵踢set) 就好了。

首先可以发现,假如 p i p_i pi 大的能放,那么肯定优先放大的。

然后根据题中 l i ≤ l i + 1 , r i ≤ r i + 1 li≤li+1,ri≤ri+1 lili+1,riri+1 的奇妙限制,可以得到这样的贪心:按照读入的顺序遍历每一个区间,将所有区间的权值存在 multiset 中。当我现在加入一个区间 i i i ,那么在此之后不会再有区间能够匹配 l i l_i li 之前的某天,所以可以把 multiset 中的区间按权值从大到小取出来,匹配 l i l_i li 之前的天。然后向 multiset 中加入 p i p_i pi ,假如 multiset 中的区间个数多于 ∑ i = l i r i a i \sum_{i=l_i}^{r_i} a_i i=liriai ,说明其中有些点无论如何也匹配不了了,这时就按权值从小到大取出区间丢掉。

换句话说, multiset 里存的就是能够匹配当前区间的天的最优的一些区间。

贪心好题,我想不到。

代码

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 3e5 + 10;
int n, m, a[N], ans, sum[N];
int le[N], ri[N], we[N], siz;
multiset<int> s;

signed main()
{
	ios::sync_with_stdio(false);
	cin >> m >> n;
	for (int i = 1; i <= n; ++ i) cin >> a[i];
	for (int i = 1; i <= n; ++ i) sum[i] = sum[i-1] + a[i];
	le[0] = 1; ri[0] = 0;
	for (int i = 1; i <= m; ++ i)
		cin >> le[i] >> ri[i] >> we[i];
	le[++m] = n+1; ri[m] = n;
	for (int i = 1; i <= m; ++ i){
		for (int j = le[i-1]; j < le[i]; ++ j){
			while (a[j] && !s.empty()){
				multiset<int>::iterator k = s.end();
				k--;
				ans += *k;
				s.erase(k); siz--;
				a[j]--;
			}
		}
		s.insert(we[i]); siz++;
		while (siz > sum[ri[i]]-sum[le[i]-1]){
			multiset<int>::iterator k = s.begin();
			s.erase(k); siz--;
		}
	}
	cout << ans << endl;
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值