• CF1007E Mini Metro


    题意:有n个车站,每站有初始人数,每一天增加ai人,容纳量为bi。每天你可以派任意辆火车,按顺序接走前K个人。求维持m天最少要多少辆。
    \(n,m\leq 200\)

    难度较大的DP。
    我们发现一旦x车站有人被接走,那么前x-1个车站一定被清空。
    利用这个性质可以DP。

    设f(x,y,0/1)表示前x个,有/无初始值坚持y时间需要的最小数目。
    g(x,y,0/1)表示在f基础上,结束后把前x-1个车站清空的最小代价。
    其中不允许接走第x个车站后面的人。
    若无解则为inf。
    转移较麻烦,可分为如下几步:
    枚举z表示最后一次接走i车站的时间。

    1. 在前z个时刻保证合法,并把前x-1个车站清空,即g(x,z,*)。
    2. 算出此时第x个车站剩余人数。并计算第x个车站在剩余的y-z时间内不爆需要的额外车的数目。
注:若需要减到负数则无解。
    3. 剩余的y-z个时间保证前x-1个合法,即f(x-1,y-z,0)。
    4. 对于g的转移,算出结束时前x-1个车站剩余人数,加上清空他们所需代价。

    注意:由于最优的f转移在清空前x-1个车站后未必最优,所以我们要分f和g分别计算。
    时间复杂度:O(nm^2)。

    代码:

    #include <stdio.h>
    #define ll long long
    #define inf 9999999999999999ll
    ll A[220],B[220],C[220];
    ll ha[220],hb[220],f[220][220][2],g[220][220][2];
    int main()
    {
        int n,m,K;
        scanf("%d%d%d",&n,&m,&K);
        for(int i=1;i<=n;i++)
        {
            scanf("%lld%lld%lld",&A[i],&B[i],&C[i]);
            A[i]-=B[i];
        }
        A[++n]=inf;C[n]=A[n];
        for(int i=1;i<=n;i++)
            ha[i]=ha[i-1]+A[i],hb[i]=hb[i-1]+B[i];
        for(int i=0;i<=n;i++)
        {
            for(int x=0;x<=m;x++)
            {
                for(int s=0;s<2;s++)
                {
                    if(i==0)
                    {
                        f[i][x][s]=g[i][x][s]=0;
                        continue;
                    }
                    f[i][x][s]=g[i][x][s]=inf;
                    for(int y=0;y<x;y++)
                    {
                        ll t=g[i][y][s];
                        if(t>=inf)continue;
                        ll z=ha[i]*s+hb[i]*(y+1)-t*K;
                        ll ms=C[i]-(x-y)*B[i],c=(z-ms+(K-1))/K;
                        if(c<0)c=0;
                        if(z-c*K>=0)
                        {
                            t=t+c+f[i-1][x-y-1][0];
                            if(t<f[i][x][s])f[i][x][s]=t;
                            ll ss=f[i-1][x-y-1][0];
                            if(ss>=inf)continue;
                            ll tt=hb[i-1]*(x-y)-ss*K;
                            tt=(tt+(K-1))/K;
                            if(tt<0)tt=0;
                            t=g[i][y][s]+c+ss+tt;
                            if(ha[i]*s+hb[i]*(x+1)-t*K>=0&&t<g[i][x][s])
                                g[i][x][s]=t;
                        }
                    }
                    if(A[i]*s+B[i]*(x+1)<=C[i])
                    {
                        ll t=f[i-1][x][s];
                        if(t<f[i][x][s])
                            f[i][x][s]=t;
                        if(t>=inf)continue;
                        ll tt=ha[i-1]*s+hb[i-1]*(x+1)-t*K;
                        tt=(tt+(K-1))/K;
                        if(tt<0)tt=0;
                        t+=tt;
                        if(t*K<=ha[i]*s+hb[i]*(x+1)&&t<g[i][x][s])
                            g[i][x][s]=t;
                    }
                }
            }
        }
        ll ans=f[n][m][1];
        printf("%lld\n",ans);
        return 0;
    }
    
  • 相关阅读:
    Oracle Relink RAC Binary Options 说明
    Oracle 10g 对象 默认 ITL 数量 测试
    Oracle 相关的专业术语 说明
    Oracle 11g 新特性 自适应游标共享(Adaptive Cursor Sharing: ACS) 说明
    symbian 学习笔记(1) 基础
    symbian 学习笔记(3) 手机独有
    计算机体系结构几个常用的知识点记录
    数据结构和算法笔记(3)
    windows mobile 通用曾抽象
    一些简单常用算法整理学习
  • 原文地址:https://www.cnblogs.com/lnzwz/p/15878742.html
Copyright © 2020-2023  润新知