地球发动机
时间限制: 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;
}