1. 程式人生 > >Gym 100829S_surf 動態規劃的優化

Gym 100829S_surf 動態規劃的優化

ac代碼 暴力 頭文件 復雜度 優化 p值 萬能 col ets

題目大意是,非你若幹個任務,任務分別對應開始時間、預期收益、持續時間三項指標,讓你從中選擇一個受益最大的方案(沒有開始時間相同的任務)。

於是,標準狀態轉移方程應當為,設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; }

Gym 100829S_surf 動態規劃的優化