[USACO2007NOVS] Milking Time S

题目描述

Bessie 可以在接下来 \(N\) 个小时内产奶,为了方便,我们把这 \(N\) 个小时 \(0\dots N-1\) 编号。

FJ 在这 \(N\) 个小时内有 \(M\) 段时间可以来给 Bessie 挤奶,第 \(i\) 段时间从 \(Start_i\) 开始到 \(End_i\) 结束,可以得到 \(Eff_i\) 加仑牛奶。

每次 FJ 给 Bessie 挤奶之后,Bessie 都要休息 \(R\) 个小时,FJ 才能开始下一次挤奶。

现在,FJ 需要您计算出 Bessie 在这 \(N\) 个小时内最多产多少奶。

输入格式

第一行有三个整数,分别表示 \(N,M,R\)

\(2\dots M+1\) 行,第 \(i+1\) 行有三个整数 \(Start_i,End_i,Eff_i\),描述一段挤奶的时间。

输出格式

输出一行一个整数表示答案。

样例 #1

样例输入 #1

12 4 2
1 2 8
10 12 19
3 6 24
7 10 31

样例输出 #1

43

提示

数据规模与约定
对于全部的测试点,保证 \(1\le N\le 10^6\)\(1\le M\le 10^3\)\(1\le Start_i<end_i\le N\)\(1\le Eff_i\le 10^6\)

先考虑最基础的暴力。每次考虑一个区间选不选,如果选,那么下一个区间的开头要和这一个区间隔至少r,否则不变。
复杂度\(O(2^n)\)。我们可以将所有的区间按照右端点排序,然后每次记录上一个区间末尾,选的时候判断差距是否大于r即可。

暴力中记录两个量,一个是上一个区间末尾,一个是现在到了第几个区间。

考虑怎样记忆化。容易发现我们可以将所有左端点和右端点+r离散化,然后就把左右端点范围缩在了m的级别。然后搜索时记录两个量,一个是到了第几个区间,一个是上一个区间右端点+r离散化的位置。如果这个位置l离散化大于等于上一个区间右端点+r的位置,那就可以选这个区间。

#include<bits/stdc++.h> 
using namespace std;
const int M=1e3+5;
int n,m,r,ans,dp[M][M*3],lsh[M*2];
struct node{
	int l,r,t;
	bool operator<(const node&n)const{
		return r<n.r;
	}
}d[M];
int dfs(int x,int y)
{
	if(x>m)
		return 0;
	if(dp[x][y]!=-1)
		return dp[x][y];
	int ret=0,
	a=lower_bound(lsh+1,lsh+2*m+1,d[x].l)-lsh,
	b=lower_bound(lsh+1,lsh+2*m+1,d[x].r+r)-lsh;
	if(a>=y)
		ret=dfs(x+1,b)+d[x].t;
	ret=max(ret,dfs(x+1,y));
	return dp[x][y]=ret;
}
int main()
{
	memset(dp,-1,sizeof(dp));
	scanf("%d%d%d",&n,&m,&r);
	for(int i=1;i<=m;i++)
		scanf("%d%d%d",&d[i].l,&d[i].r,&d[i].t),lsh[2*i-1]=d[i].r+r,lsh[2*i]=d[i].l;
	sort(d+1,d+m+1);
	sort(lsh+1,lsh+2*m+1);
	printf("%d",dfs(1,0));
	return 0;
}
posted @ 2022-05-28 14:46  灰鲭鲨  阅读(38)  评论(0编辑  收藏  举报