upc 地球发动机 线性dp + 二分

地球发动机
时间限制: 1 Sec 内存限制: 128 MB

题目描述
“啊,地球,我的流浪地球……”——《流浪地球》
在一条直线上,从左到右排列着n台地球发动机,每台发动机有着固定的位置坐标Ai和功率Pi,保证Ai<Ai+1。此外,由于地球发动机的特性,每台发动机还有一个参数Xi,如果一台发动机运行,则坐标范围在[Ai,Ai+Xi]的其它发动机就无法运行。现在你想让正在运行的发动机总功率最大,请输出这个总功率。

输入
第一行一个整数n,意义如上所述。
接下来n行,每行三个整数Ai,Pi,Xi,意义如题面所述。

输出
一行一个整数,表示可能的最大功率。
样例输入 Copy
4
2 5 1
5 4 3
8 10 3
9 2 2
样例输出 Copy
15
提示
对于20%的数据,n≤10,0<Ai,Pi,Xi≤10;
对于50%的数据,n≤2000,0<Ai,Pi,Xi≤105;
对于100%的数据,n≤105,0<Ai,Pi,Xi≤109。

一开始没看完题为了快点直接写了个区间贪心,结果发现区间还带权值,让后就放弃了贪心的做法,开始考虑dp。
f [ i ] [ j ] 表示 当前选到第 i 个发动机,j 表示选或者不选。
让后就一直正向做dp,wa到自闭了。找师傅问了下,结果是要反向做dp,让后每个点转移状态是从前面转移过来,这是为了防止产生后效性,也就是说从前面转移的时候,需要考虑前面的发动机能不能让他熄火,时间复杂度剧增,而且情况还有很多,所以可以考虑反向dp,每次选择这个点 i 的时候用二分找到位置大于 a [ i ] + x [ i ] 的点的 f [ t ] [ 0 ] 和 f [ t ] [ 1 ] 中大的一个状态转移过来,加上 p [ i ] 即可。不选择这个点的时候, 直接从 f [ i + 1 ] 的两个状态转移过来即可。

#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#define X first
#define Y second
using namespace std;

typedef long long LL;
typedef pair<int,int> PII;

const int N=100010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n;
int a[N],p[N],x[N];
LL f[N][2];
LL ans;

int main()
{
//	ios::sync_with_stdio(false);
//	cin.tie(0);

	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%d%d%d",&a[i],&p[i],&x[i]);

	for(int i=n;i>=1;i--)
	{
		int t=upper_bound(a+1,a+1+n,a[i]+x[i])-a;
		f[i][1]=max(f[t][1],f[t][0])+p[i];
		f[i][0]=max(f[i+1][1],f[i+1][0]);
	}
	
	printf("%lld\n",max(f[1][0],f[1][1]));




	return 0;
}










评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值