1. 程式人生 > >bzoj1233: [Usaco2009Open]幹草堆tower 單調隊列優化dp

bzoj1233: [Usaco2009Open]幹草堆tower 單調隊列優化dp

== name char 也不會 hid blog -m opened frame

又是一道單調隊列優化dp的題目 這道題呢 先要了解一個結論,在多種可行的堆疊方案中,至少有一種能使層數最高的方案同時使得底邊最短。即底邊最短的,層數一定最高。 這個是zkw大神得出的 我也不會證明來著 反正這樣之後我們就可以得出正確的方法了

遞推式 F[i]=min(sum[j-1]-sum[i-1]) j>i 且 sum[j-1]-sum[i-1]>=F[j] 易得在滿足的條件下j當然是越小越好了嘛 而這樣得出的方程又滿足一定的單調性 這樣調整之後隊首就是我們要的答案啦

又對於轉移條件 f[j]<=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】那k一定不是最優解就可以舍棄啦

剩下的看看代碼吧

技術分享
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int M=100007;
int read(){
    int ans=0,f=1,c=getchar();
    while(c<0||c>9){if(c==-) f=-1; c=getchar();}
    
while(c>=0&&c<=9){ans=ans*10+(c-0); c=getchar();} return ans*f; } int f[M],g[M],sum[M],q[M],head,tail,n,w; int main() { n=read(); for(int i=1;i<=n;i++) w=read(),sum[i]=sum[i-1]+w; q[0]=n+1; for(int i=n;i;i--){ 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&&f[i]-sum[i-1]<=f[q[tail]]-sum[q[tail]-1]) tail--; q[++tail]=i; } printf("%d\n",g[1]); return 0; }
View Code

bzoj1233: [Usaco2009Open]幹草堆tower 單調隊列優化dp