1. 程式人生 > >BZOJ P1233 幹大發彩草票平臺出租堆tower 【單調隊列優化DP】

BZOJ P1233 幹大發彩草票平臺出租堆tower 【單調隊列優化DP】

如果 follow for oid memcpy 狀態 模型 putchar sin

題目分析:大發彩草票平臺出租 haozbbs.com Q1446595067

我們用F[I]
表示用第I N包做草堆的時候最底下一層的最短長度,G[I]

記錄此時能到達的最高高度,顯然可以得到如下的一個狀態轉移方程:
if(J>I,F[J]<=Sum[J?1]?Sum[I?1])

F[I]=min(Sum[J?1]?Sum[I?1]),G[I]=G[J]+1

由於這大發彩草票平臺出租樣的做法時間復雜度是n2,所以我們考慮優化DP。我們註意到F[I]的值總是只與Sum[J?1]?Sum[I?1]的大小有關,也就是我們只需要考慮能夠更新答案,能夠發生狀態轉移的話那麽必須滿足下面的式子:
F[J]≤Sum[J?1]?Sum[I?1]

Sum[i?1]≤Sum[J?1]?F[J]

通過這個式子我們可以發現如果能夠更新答案我們一定要滿足式子右邊盡量小,也就是說,如果存在以下的式子,那麽一定不能夠更新答案:
K>J,Sum[K?1]?F[K]≥Sum[J?1]?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;
}

BZOJ P1233 幹大發彩草票平臺出租堆tower 【單調隊列優化DP】