当前位置: 首页 > article >正文

洛谷 P4644 USACO05DEC Cleaning Shift/AT_dp_w Intervals 题解

1.Cleaning Shift

题意

约翰的奶牛们从小娇生惯养,她们无法容忍牛棚里的任何脏东西。约翰发现,如果要使这群有洁癖的奶牛满意,他不得不雇佣她们中的一些来清扫牛棚,约翰的奶牛中有 n n n 头愿意通过清扫牛棚来挣一些零花钱。

由于在某个时段中奶牛们会在牛棚里随时随地地乱扔垃圾,自然地,她们要求在这段时间里,无论什么时候至少要有一头奶牛正在打扫。需要打扫的时段从某一天的第 s t st st 秒开始,到第 e n en en 秒结束 。注意这里的秒是指时间段而不是时间点,也就是说,每天需要打扫的总时间是 e n − s t + 1 en-st+1 enst+1 秒。

约翰已经从每头牛那里得到了她们愿意接受的工作计划:对于某一头牛,她每天都愿意在笫 l … r l \ldots r lr 秒的时间段内工作 ( s t ≤ l ≤ r ≤ e n ) (st \leq l \leq r \leq en) (stlren) ,所要求的报酬是 k k k 美元 ( 0 ≤ k ≤ 500000 ) (0 \leq k \leq 500000) (0k500000)。与需打扫时段的描述一样,如果一头奶牛愿意工作的时段是每天的第 10 … 20 10 \ldots 20 1020 秒,那她总共工作的时间是 11 11 11 秒,而不是 10 10 10 秒。

约翰一旦决定雇佣某一头奶牛,就必须付给她全额的工资,而不能只让她工作一段时间,然后再按这段时间在她愿意工作的总时间中所占的百分比来决定她的工资。现在请你帮约翰决定该雇佣哪些奶牛以保持牛棚的清洁,当然,在能让奶牛们满意的前提下,约翰希望使总花费尽量小。

1 ≤ n ≤ 10000 , 0 ≤ s t ≤ e n ≤ 86399 1 \leq n \leq 10000,0 \leq st \leq en \leq 86399 1n10000,0sten86399

思路

最小权线段覆盖,CSPS2024就倒在这种类型。

套路地,我们对每一只奶牛的工作区间按右端点排序。

定义 f r f_r fr表示从 s t st st清理到 r r r的最小花费,那么朴素的,对于一只工作时间段右端点恰为 r r r的奶牛 t t t,我们可以写出转移式子:
f r = min ⁡ r t = r { k t + min ⁡ i = 1 l t − 1 f i } f_r=\min_{r_t=r} \left \{k_t+ \min_{i=1}^{l_t-1}f_i\right \} fr=rt=rmin{kt+i=1minlt1fi}

看到区间最小值如果暴力做就 Θ ( n 2 ) \Theta(n^2) Θ(n2),然而显然的我们可以用线段树求区间最小值来凹时间。

最后就是一些细节:考虑其花费最大值都去到了 500000 500000 500000,那么 I N F \rm INF INF值要给大一点,开long long吧别吝啬那点空间;然后就是给最好给时间点都加 1 1 1 0 0 0,不然减 1 1 1的时候出现 − 1 -1 1就段错误了。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls u<<1
#define rs u<<1|1 
const ll N=1e5+9,inf=3e14;
ll n,st,en;
struct term
{
	ll l,r,k;
};
vector<term>p[N];
ll f[N];
struct SegT
{
	struct node
	{
		ll mi;
	}T[N<<2];
	void pushup(ll u)
	{
		T[u].mi=min(T[ls].mi,T[rs].mi);
	}
	void build(ll u,ll l,ll r)
	{
		T[u].mi=inf;
		if(l==r)return;
		ll mid=(l+r)>>1;
		build(ls,l,mid);
		build(rs,mid+1,r);
		pushup(u);
	}
	void modify(ll u,ll l,ll r,ll x,ll k)
	{
		if(l==r)
		{
			T[u].mi=min(T[u].mi,k);
			return;
		}
		ll mid=(l+r)>>1;
		if(x<=mid)modify(ls,l,mid,x,k);
		if(x>mid)modify(rs,mid+1,r,x,k);
		pushup(u);
	}
	ll query(ll u,ll l,ll r,ll ql,ll qr)
	{
		if(qr<l||r<ql)return inf;
		if(ql<=l&&r<=qr)return T[u].mi;
		ll mid=(l+r)>>1,ret=inf;
		if(ql<=mid)ret=min(ret,query(ls,l,mid,ql,qr));
		if(qr>mid)ret=min(ret,query(rs,mid+1,r,ql,qr));
		return ret;
	}
}A;
int main()
{
	scanf("%lld%lld%lld",&n,&st,&en);
	st++,en++;
	for(int i=1;i<=n;i++)
	{
		ll l,r,k;
		scanf("%lld%lld%lld",&l,&r,&k);
		l++,r++;
		l=max(l,st);
		r=min(r,en);
		p[r].push_back((term){l,r,k});//对右端点排序
	}
	for(int i=st;i<=en;i++)
	f[i]=inf;
	A.build(1,st-1,en);
	A.modify(1,st-1,en,st-1,0);//不用干就0咯
	f[st-1]=0;
	for(int i=st;i<=en;i++)//枚举右端点r
	{
		for(auto x:p[i])//遍历奶牛
		{
			f[i]=min(f[i],x.k+A.query(1,st-1,en,x.l-1,i));
			A.modify(1,st-1,en,i,f[i]);//贡献扔进右端点对应线段树
		}
	}
	if(f[en]==inf)puts("-1");
	else printf("%lld",f[en]);
	return 0;
}

2.Intervals

题意

给定 m m m条规则,形如 l , r , k l,r,k l,r,k,对于一个 01 01 01串,其分数的定义为:对于第 i i i条规则,若该串在区间 [ l , r ] [l,r] [l,r]中至少有一个 1 1 1,则该串的分数增加 k k k

求长度为 n n n 01 01 01串最大分数。

1 ≤ n , m ≤ 2 × 1 0 5 , − 1 0 9 ≤ k ≤ 1 0 9 1\le n,m\le 2\times 10^5,-10^9\le k \le 10^9 1n,m2×105,109k109

思路

f r , j f_{r,j} fr,j表示枚举到位置 r r r,上一个 1 1 1放在 j j j处的最大答案。
f r , j = max ⁡ j = 1 r − 1 { f r − 1 , j } + ∑ i : l i ≤ r k i f_{r,j}=\max_{j=1}^{r-1}\{f_{r-1,j}\}+\sum_{i:l_i\le r}k_i fr,j=j=1maxr1{fr1,j}+i:lirki

那就还是线段树优化dp了。

同样,根据右端点排序,线段树维护贡献最大值即可,对于所有满足 l i ≤ r , r i = r l_i\le r,r_i=r lir,ri=r的奶牛 i i i的分数和,也扔上线段树区间加并入贡献即可。

代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls u<<1
#define rs u<<1|1
const ll N=2e5+9,inf=0x7f7f7f7f;
ll n,m;
struct term
{
	ll l,r,k;
};
vector<term>p[N];
struct SegT
{
	struct node
	{
		ll ma;
		ll tag;
	}T[N<<2];
	void pushup(ll u)
	{
		T[u].ma=max(T[ls].ma,T[rs].ma);
	}
	void pushdown(ll u)
	{
		if(T[u].tag)
		{
			T[ls].tag+=T[u].tag;
			T[ls].ma+=T[u].tag;
			T[rs].tag+=T[u].tag;
			T[rs].ma+=T[u].tag;
			T[u].tag=0;
		}
	}
	void modify(ll u,ll l,ll r,ll ql,ll qr,ll k)
	{
		if(ql<=l&&r<=qr)
		{
			T[u].ma+=k;
			T[u].tag+=k;
			return;
		}
		pushdown(u);
		ll mid=(l+r)>>1;
		if(ql<=mid)modify(ls,l,mid,ql,qr,k);
		if(qr>mid)modify(rs,mid+1,r,ql,qr,k);
		pushup(u);
	}
}A;
int main()
{
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=m;i++)
	{
		ll l,r,k;
		scanf("%lld%lld%lld",&l,&r,&k);
		p[r].push_back({l,r,k});//右端点排序 
	}
	for(int i=1;i<=n;i++)
	{
		A.modify(1,1,n,i,i,max(0ll,A.T[1].ma));
		for(term x:p[i])
		A.modify(1,1,n,x.l,i,x.k);//右端点加贡献 
	}
	printf("%lld",max(0ll,A.T[1].ma));
	return 0;
}

http://www.kler.cn/a/557126.html

相关文章:

  • 体育品牌排行榜前十名:MLB·棒球1号位
  • 蓝禾,oppo,游卡,汤臣倍健,康冠科技,作业帮,高途教育25届春招内推
  • QUdpSocket的readyRead信号只触发一次
  • python-leetcode-两两交换链表中的节点
  • Scrapy:Downloader下载器设计详解
  • Open WebUI 是什么
  • 常用Web性能指标
  • 游戏引擎学习第117天
  • 在Ubuntu 22.04 LTS 上安装 MySQL两种方式:在线方式和离线方式
  • 行业分析---对自动驾驶规控算法的思考
  • 地震后房屋建筑损坏程度分割数据集labelme格式1170张3类别
  • 从零开始用react + tailwindcs + express + mongodb实现一个聊天程序(一)
  • leetcode hot100-32 随机链表的复制
  • react+typescript,初始化与项目配置
  • 制造行业CRM选哪家?中大型企业CRM选型方案
  • USC安防平台之地图临近资源列表
  • 构建智能AI数字人:一站式源码开发指南
  • CAN 分析框架 CANToolz
  • html中iframe标签 隐藏滚动条
  • 微信小程序模仿快播标签云滚动特效