1. 程式人生 > >BZOJ P1233 乾草堆tower 【單調佇列優化DP】

BZOJ P1233 乾草堆tower 【單調佇列優化DP】

題目分析:

我們用F[I]表示用第IN包做草堆的時候最底下一層的最短長度,G[I]記錄此時能到達的最高高度,顯然可以得到如下的一個狀態轉移方程:

if(J>I,F[J]<=Sum[J1]Sum[I1])
F[I]=min(Sum[J1]Sum[I1]),G[I]=G[J]+1
由於這樣的做法時間複雜度是n2,所以我們考慮優化DP。我們注意到F[I]的值總是隻與Sum[J1]Sum[I1]的大小有關,也就是我們只需要考慮能夠更新答案,能夠發生狀態轉移的話那麼必須滿足下面的式子:
F[J]Sum[J1]Sum[I1]
Sum[i1]Sum[J1]F[J]
通過這個式子我們可以發現如果能夠更新答案我們一定要滿足式子右邊儘量小,也就是說,如果存在以下的式子,那麼一定不能夠更新答案:
K>J,Sum[K1]F[K]Sum[J1]F[J]
分析到這裡,一個單調佇列優化
DP
的模型也就湧現出來了,下面給出參考程式碼:
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define DB double
#define SG string
#define LL long long
#define Fp(A,B,C,D) for(A=B;A<=C;A+=D)
#define Fm(A,B,C,D) for(A=B;A>=C;A-=D)
#define Clear(A) memset(A,0,sizeof(A))
#define Copy(A,B) memcpy(A,B,sizeof(A)) using namespace std; const LL Max=1e5+5; const LL Mod=1e9+7; const LL Inf=1e18; LL N,F[Max],G[Max],Q[Max],Sum[Max]; inline LL Read(){ LL X=0;char CH=getchar();bool F=0; while(CH>'9'||CH<'0'){if(CH=='-')F=1;CH=getchar();} while(CH>='0'&&CH<='9'){X=(X<<1)+(X<<3)+CH-'0';CH=getchar();} return F?-X:X; } inline void Write(LL X){ if(X<0)X=-X,putchar('-'); if(X>9)Write(X/10); putchar(X%10+48); } int main(){ LL I,J,K; N=Read(); Fp(I,1,N,1){ Sum[I]=Sum[I-1]+Read(); }LL Head=1,Tail=1; Q[1]=N+1; Fm(I,N,1,1){ while(Head<Tail&&Sum[Q[Head+1]-1]-Sum[I-1]>=F[Q[Head+1]]){ ++Head; }F[I]=Sum[Q[Head]-1]-Sum[I-1];G[I]=G[Q[Head]]+1; while(Head<=Tail&&Sum[Q[Tail]-1]-F[Q[Tail]]<=Sum[I-1]-F[I]){ --Tail; }Q[++Tail]=I; }Write(G[1]); return 0; }