题目大意是,非你若干个任务,任务分别对应开始时间、预期收益、持续时间三项指标,让你从中选择一个受益最大的方案(没有开始时间相同的任务)。
于是,标准状态转移方程应当为,设DP[K]为选择了前K个任务的最大收益,后面转移为DP[K+1]=MAX且能够共存的(DP[I]);很容易想到N^2的暴力更新,但是这题数量太大,会炸得连渣都不剩。于是需要优化到较低的数量级(比如NLOGN)
注意到,我们也许不用对某个任务来选取前K个的最大值,不容易想到优化但是想想刘汝佳同志的话——不方便直接求解的时候想想更新状态看看,于是就变成了状态更新公式而不是状态转移方程。——对于求得的DP[K]更新所有合法 的,大于K的DP值。注意到,当前序列已经经过了排序,所以,当找到第一个合法的DP[P]P>K时候,就会有P+1也是合法的状态,因此很容易想到树状数组相对最大值+二分查找确定位置(只要有比较函数就可以写二分)。最后复杂度是NLOGN。
另外根据某些奇怪的树上的书法,,任何一个动态规划的优化算法都应当从如下三个状态进行考虑:
1、状态总数 N N
2、决策数 N 1
3、状态转移时间复杂度 1 LOGN
分别对应原始DP和优化后的DP
AC代码如下:考虑到没有校园网所以在VJ上面交的。。。于是投篮用了万能头文件,好孩子不要学我哟~
#include<bits/stdc++.h> using namespace std; const long long MAXN=300233; class Mession { public: long long a,b,p; };Mession messions[MAXN]; long long tree[MAXN]; long long dp[MAXN]; long long n; void insert(int pos,long long key) { while(pos<=n) { tree[pos]=max(key,tree[pos]); pos+=pos&(-pos); } } long long getSum(int pos) { long long ans=0; while(pos) { ans=max(tree[pos],ans); pos-=pos&(-pos); }return ans; } bool cmp(Mession m1,Mession m2) { return m1.a<m2.a; } void init() { cin>>n; for(int i=1;i<=n;++i) { cin>>messions[i].a>>messions[i].p>>messions[i].b; messions[i].b+=messions[i].a; }sort(messions+1,messions+n+1,cmp); long long ans=0; for(int i=1;i<=n;++i) { dp[i]=messions[i].p; dp[i]+=getSum(i); Mession mm;mm.a=messions[i].b; int pos=lower_bound(messions+1,messions+1+n,mm,cmp)-messions; insert(pos,dp[i]); ans=max(dp[i],ans); } cout<<ans<<endl; } int main() { cin.sync_with_stdio(false); init(); return 0; }
时间: 2024-10-23 22:08:51