zoukankan      html  css  js  c++  java
  • bzoj5164: 餐厅计划问题(三分+贪心)

      网络流经典题里餐巾计划的加强版...天数变成了$10^5$,那就不能用费用流做了...

      考虑费用流的时候,单位费用随流量的增加而减少,也就是说费用其实是个单峰(下凸)函数。

      那么可以三分要买的餐巾个数,求费用可以用贪心。

      新买的没用就用新买的,否则能慢洗的慢洗,不能慢洗的拿最晚的快洗后可以当天用的去快洗。

      有一个错误的贪心是慢洗和快洗的都拿最早的,这样可能会导致快洗的本来可以洗时间更晚一些的,却洗了比较早的餐巾,而这些餐巾本可以在接下来的一天里通过慢洗来省下更多的钱。

    #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
    ", ans);
    }
    View Code
  • 相关阅读:
    luogu 3388 【模板】割点(割顶)
    bzoj 3624 免费道路
    bzoj 1179 Atm
    bzoj 2428 均分数据
    luogu 4429 染色
    luogu 4427 求和
    luogu 1121 环状最大两段子段和
    hdu 4777 Queue
    hdu 5492 Find a path
    hdu 5441 Travel
  • 原文地址:https://www.cnblogs.com/Sakits/p/8453002.html
Copyright © 2011-2022 走看看