Codeforce 1061 :D. TV Shows(multiset + 贪心 + 构造)

10 篇文章 0 订阅
6 篇文章 0 订阅

题目大意:有 n 个电视节目,每个节目有一个播放时间[ai,bi],你可以租用电视机来播放节目,租用一台电视机要先付 x x x(类似定金什么的),如果你在[a,b]时间段租用,你需要付租用的费用: y ∗ ( b − a ) y * (b - a) y(ba)。当电视机播放一个节目时,电视机不能中途跳转到播放其它节目,一个节目被电视机播放时,也不能播到一半然后转到其它电视机去播放。问如何使租用电视机使得你可以播放所有的节目,且花费的费用最少。
在这里插入图片描述

题解:跟着样例分析一下,如果租用一台电视连续播放好几个节目,例如两个,那么你将多付两个节目之间的间隔时间的钱(后一个节目的开始时间扣去前一个节目的结束时间),如果你另外租一台电视机来播放另外一个节目,你不用多付节目之间间隔时间的租用费,但你需要付另外一台电视机的定金,思考一下会发现:当两个节目之间的间隔小于等于 ⌊ x y ⌋ \lfloor \frac{x}{y}\rfloor yx,租一台电视机连着播放是比较赚的,否则另外租一台比较赚,如果两个节目时间段相交,那么只能另外再租一台了。

可以贪心构造租用方案,将节目按左端点排序(这个排序只是为了让决策有序),判断当前节目可以被那个已经租用的电视机播放:设当前节目的左端点为 l [ i ] l[i] l[i],租用的第 k台电视目前播放的最后一个节目的右区间是 R [ k ] R[k] R[k],查找是否存在已租用的电视播放的最后一个节目的右区间在 [ l [ i ] − d , l [ i ] − 1 ] [l[i] - d,l[i] - 1] [l[i]d,l[i]1]范围内,找尽量靠右的,间隔时间越短你多付的钱越少,如果不存在这样的电视那么你另外租一台来播放这个节目一定更赚。

维护可以用multiset,注意已租用的电视机播放的节目有增加时需要删除掉原来这个电视,然后将新的插入到set中,整体复杂度为 n ∗ l o g n n*logn nlogn(也可以考虑用权值线段树,但需要在叶子结点维护一个桶记录所有的电视机,空间开销比较大,还需要离散化之类的操作)

代码

#include<bits/stdc++.h>
using namespace std;
#define lson rt << 1,l,mid
#define rson rt << 1 | 1,mid + 1,r
const int maxn = 2e6 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
int L[maxn],R[maxn],cnt;
int n,x,y;
int t[maxn],tot,p;
struct ss{
	int l,r;
	bool operator < (const ss & rhs) const {
		if(l == rhs.l) return r < rhs.r;
		return l < rhs.l;
	}
}a[maxn];
int mul(int a,int b) {
	return (int)((1ll * a * b) % mod);
}
struct tt{
	int l,r,id;
	tt(int li = 0,int ri = 0,int idi = 0) {
		l = li;r = ri;id = idi;
	}
	bool operator < (const tt & rhs) const {
		if(r == rhs.r) return l < rhs.l;
		return r < rhs.r;
	}
};
multiset<tt> st;
int main() {
	scanf("%d%d%d",&n,&x,&y);
	tot = cnt = 0;
	int d = x / y;
	for(int i = 1; i <= n; i++) {
		scanf("%d%d",&a[i].l,&a[i].r);
	}
	sort(a + 1,a + n + 1);
	for(int i = 1; i <= n; i++) {
		auto t = st.lower_bound(tt(0,a[i].l,0));
		auto u = t;
		if(u != st.begin()) u--;
		if(t == st.begin() || u -> r < a[i].l - d) {
			++cnt;
			L[cnt] = a[i].l;
			R[cnt] = a[i].r;
			st.insert(tt(L[cnt],R[cnt],cnt));
		}
		else {
			int z = u -> id;
			st.erase(u);
			R[z] = a[i].r;
			st.insert(tt(L[z],R[z],z));
		}
	}
	ll ans = mul(cnt,x);
	for(int i = 1; i <= cnt; i++) {
		ans += mul(R[i] - L[i],y);
		ans %= mod;
	}
	printf("%lld\n",ans);
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值