bzoj5164: 餐廳計劃問題(三分+貪心)

  網絡流經典題裏餐巾計劃的增強版...天數變成了$10^5$,那就不能用費用流作了...ios

  考慮費用流的時候,單位費用隨流量的增長而減小,也就是說費用實際上是個單峯(下凸)函數。網絡

  那麼能夠三分要買的餐巾個數,求費用能夠用貪心。ide

  新買的沒用就用新買的,不然能慢洗的慢洗,不能慢洗的拿最晚的快洗後能夠當天用的去快洗。函數

  有一個錯誤的貪心是慢洗和快洗的都拿最先的,這樣可能會致使快洗的原本能夠洗時間更晚一些的,卻洗了比較早的餐巾,而這些餐巾本能夠在接下來的一天裏經過慢洗來省下更多的錢。spa

#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int maxn=500010, inf=1e9;
struct poi{int tim, rest;}q1[maxn], q2[maxn], q3[maxn];
int d, n1, n2, c1, c2, tc, ans=inf;
int t[maxn];
inline void read(int &k)
{
    int f=1; k=0; char c=getchar();
    while(c<'0' || c>'9') c=='-'&&(f=-1), c=getchar();
    while(c<='9' && c>='0') k=k*10+c-'0', c=getchar();
    k*=f;    
} 
inline int f(int x)
{
    int ans=(tc-c2)*x;
    int l1, r1, l2, r2, l3, r3;
    l1=l2=l3=r1=1; r2=r3=0;
    q1[1].tim=-inf; q1[1].rest=x;
    for(int i=1;i<=d;i++)
    {
        while(l1<=r1 && q1[l1].tim+n1<=i) q2[++r2]=q1[l1++];
        while(l2<=r2 && q2[l2].tim+n2<=i) q3[++r3]=q2[l2++];
        int rest=t[i];
        while(rest)
        {
            if(l3<=r3)
            {
                if(q3[r3].rest>=rest) q3[r3].rest-=rest, ans+=rest*c2, rest=0;
                else ans+=q3[r3].rest*c2, rest-=q3[r3--].rest;
            }
            else if(l2<=r2)
            {
                if(q2[r2].rest>=rest) q2[r2].rest-=rest, ans+=rest*c1, rest=0;
                else ans+=q2[r2].rest*c1, rest-=q2[r2--].rest;
            }
            else return inf;
        }
        q1[++r1].tim=i; q1[r1].rest=t[i];
    }
    return ans;
}
int main()
{
    read(d); read(n1); read(n2); read(c1); read(c2); read(tc);
    int l=1, r=0;
    for(int i=1;i<=d;i++) read(t[i]), r+=t[i];
    if(n1>n2) swap(n1, n2), swap(c1, c2);
    if(c1<c2) n2=n1, c2=c1;
    while(r-l>4)
    {
        int mid1=l+(r-l)/3, mid2=l+(r-l)*2/3;
        if(f(mid1)==inf || f(mid1)>f(mid2)) l=mid1;
        else r=mid2;
    }
    for(int i=l;i<=r;i++) ans=min(ans, f(i));
    printf("%d\n", ans);
}
View Code
相關文章
相關標籤/搜索