1. 程式人生 > >BZOJ_1229_[USACO2008 Nov]toy 玩具_三分+貪心

BZOJ_1229_[USACO2008 Nov]toy 玩具_三分+貪心

++ 便宜 多少 -- esp check 比較 usaco 出了

BZOJ_1229_[USACO2008 Nov]toy 玩具_三分+貪心

Description

玩具 [Chen Hu, 2006] Bessie的生日快到了, 她希望用D (1 <= D <= 100,000; 70%的測試數據都滿足 1 <= D <= 500)天來慶祝. 奶牛們的註意力不會太集中, 因此Bessie想通過提供玩具的方式來使它們高興. 她已經計算出了第i天需要的玩具數T_i (1 <= T_i <= 50). Bessie的幼兒園提供了許多服務給它們的奶牛程序員們, 包括一個每天以Tc (1 <= Tc <= 60)美元賣出商品的玩具店. Bessie想盡可能的節省錢, 但是Farmer John擔心沒有經過消毒的玩具會帶來傳染病(玩具店賣出的玩具是經過消毒的). 有兩種消毒的方式. 第1種方式需要收費C1美元, 需要N1個晚上的時間; 第2種方式需要收費 C2美元, 需要N2個晚上的時間(1 <= N1 <= D; 1 <= N2 <= D; 1 <= C1 <= 60; 1 <= C2 <= 60). Bessie在party結束之後把她的玩具帶去消毒. 如果消毒只需要一天, 那麽第二天就可以拿到; 如果還需要一天, 那麽第三天才可以拿到. 作為一個受過教育的奶牛, Bessie已經了解到節約的意義. 幫助她找到提供玩具的最便宜的方法.

Input

* 第 1 行: 六個用空格隔開的整數 D, N1, N2, C1, C2, Tc

* 第 2..D+1 行: 第 i+1 行包含一個整數: T_i

Output

第 1 行: 提供玩具所需要的最小費用.

Sample Input

4 1 2 2 1 3
8
2
1
6

Sample Output

35


三分到底買多少玩具。

打個表發現確實是單峰函數。。證明的話不會。

可能是因為跑費用流時單位費用和最短路單調吧。

貪心還是比較簡單的。

優先用已經買好的,因為這個費用是0。

否則用慢洗的,這個可以維護一個指針。

如果慢洗洗不過來就用快洗,快洗要盡可能用最近剩下的,因為要給慢洗留出時間,用一個棧來維護。

註意這裏的慢洗,快洗是根據數據的,費用少的那個作為慢洗(不管時間)

代碼:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define N 100050
int c1,c2,n1,n2,n,t[N],tc,b[N],S[N],top;
int check(int x) {
    int re=x*tc,i,l=1; top=0;
    for(i=1;i<=n;i++) b[i]=t[i];
    for(i=1;i<=n;i++) {
        int lft=t[i];
        if(x>=lft) x-=lft,lft=0;
        else lft-=x,x=0;
        while(l<=i-n1&&lft) {
            if(lft<=b[l]) re+=c1*lft,b[l]-=lft,lft=0;
            else re+=c1*b[l],lft-=b[l],b[l]=0,l++;
        }
        while(top&&lft) {
            int u=S[top-1];
            if(lft<=b[u]) re+=c2*lft,b[u]-=lft,lft=0;
            else re+=c2*b[u],lft-=b[u],b[u]=0,top--;
        }
        if(i-n2+1>=1) S[top++]=i-n2+1;
        if(lft) return 1<<30;
    }
    return re;
}
int main() {
    scanf("%d%d%d%d%d%d",&n,&n1,&n2,&c1,&c2,&tc);
    if(c1>c2) swap(c1,c2),swap(n1,n2);
    int i,sum=0;
    for(i=1;i<=n;i++) scanf("%d",&t[i]),sum+=t[i];
    int l=t[1],r=sum;
    while(r-l>6) {
        int m1=(l+l+r)/3,m2=(l+r+r)/3;
        if(check(m1)<check(m2)) r=m2;
        else l=m1;
    }
    int ans=1<<30;
    for(i=l;i<=r;i++) ans=min(ans,check(i));
    printf("%d\n",ans);
}

BZOJ_1229_[USACO2008 Nov]toy 玩具_三分+貪心