zoukankan      html  css  js  c++  java
  • Luogu 5017 NOIP2018普及组T3 摆渡车 (斜率优化 + 必要的转移进行剪枝)

    题意:

      有 名同学要乘坐摆渡车从人大附中前往人民大学,第 位同学在第 ti 分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。

      凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?

      本人感觉自己语文不是那么的好,无法概括。

    细节:

      咳咳,此题细节都在题意之中嘻嘻嘻,原来懒还有这个好处。

    分析:

      round1:从时间入手状态迎刃而解:f[i] 表示以 i 作为发车时间的最小等车时间之和。

      则转移就为:f[i] = min{ f[j] + Σj<tk≤i i-t}

      但是这个转移不免需要循环计算求和的内容,我们需要考虑将其利用 O(1) 进行计算完毕,考虑将这个式子进行打开:

        Σj<tk≤i i-tk = i×Σj<tk≤i 1 - Σj<tk≤i tk,不难发现此时我们只需要预处理出 t出现位置的前缀数组 cnt[i],以及 tk 出现位置的值的前缀和 sum[i]。

      这样方程进行进一步转化:f[i] = min{ f[j] + ( cnt[i] - cnt[j] ) × i - ( sum[i] - sum[j] ) }

      最后观察其是否存在单调性,显然上方的 1D/1D 的动态规划需要进行斜率优化了,裸体希望有这些意识吧,常规套路,最后只需要维护一个斜率:

        k = ( f[j2] + sum[j2] - f[j1] - sum[j1] ) / (cnt[j2] - cnt[j1]) 单调递增即可,具体方法详见本人的第一篇博客。 

      round2:确实从时间入手是一种思路,但是对于较小的 n 和 m 很多选手应该也会有想法,不难发现对于第 i 个人对应的等待时间 t它的上车时间是有一定的范围的,它就是[ ti , ti + m),因为当超出这个范围时要么是等车的人还没来,要么等车的人能乘坐上一班车子前往目的地,所以我们可以考虑一个状态:f[i][j] 表示第 i 个人乘车切在 ti + j 的时间中上了车的最小等车时间,其状态必须保证 i + 1 这个人无法上车,且 i 之前可能有人跟 i 一起在车上。

      不难发现对于 i 之后的一个位置 k 其中这段区间 [i+1 , k] 的人上车时间可以进行计算,tmp 表示这段人的上车时间 = t[i] + j + m - t[i+k],所以我们出现了最原始的转移:

        f[k][tmp] = f[i][j] + Σi+1<=x<=k(tmp + t[k] - t[x])

      仍然需要把上方的转移优化成 O(1),使用一个裸的前缀和就可以优化掉了:

        f[k][tmpf[i][jtmt[k× − − ( sumt[k− sumt[i)

      最后这个方程仍然可以进行优化,通过把 "我为人人" -> "人人为我" 就可以再一次进行斜率优化时间复杂度就可以变为 O(n),本人比较懒开始拒绝思考了。

    代码:

    Round1:
    
    #include<bits/stdc++.h>
    #define MAXT 4000505
    using namespace std;
    
    int n, m, cnt[MAXT], sum[MAXT], f[MAXT], que[MAXT], Maxt;
    
    int main(){
        scanf("%d%d", &n, &m);
        for (int i=1; i<=n; i++){
            int x;
            scanf("%d", &x);
            cnt[x]++, sum[x]+=x;
            Maxt=max(Maxt, x);
        }
        for (int i=1; i<Maxt+m; i++) cnt[i]+=cnt[i-1], sum[i]+=sum[i-1];
        int head=1, tail=0;
        for (int i=1; i<Maxt+m; i++){
            if (i>=m) {
                while (head<tail && (f[que[tail]]+sum[que[tail]]-f[que[tail-1]]-sum[que[tail-1]])*(cnt[i-m]-cnt[que[tail]])>=(f[i-m]+sum[i-m]-f[que[tail]]-sum[que[tail]])*(cnt[que[tail]]-cnt[que[tail-1]])) --tail;
                que[++tail]=i-m;
            }
            while (head<tail && i*(cnt[que[head+1]]-cnt[que[head]])>=(f[que[head+1]]+sum[que[head+1]]-f[que[head]]-sum[que[head]])) ++head;
            f[i]=cnt[i]*i-sum[i];
            if (head<=tail) f[i]=min(f[i], f[que[head]]+(cnt[i]-cnt[que[head]])*i-(sum[i]-sum[que[head]]));
        }
        int ans=1000000000;
        for (int i=Maxt; i<Maxt+m; i++) ans=min(ans, f[i]);
        printf("%d
    ", ans);
        return 0;
    } 
    Round2:
    
    #include<bits/stdc++.h>
    using namespace std;
    int t[501],s[501],f[501][101];
    const int inf=2139062143;
    inline int read()
    {
        int neg=1,x=0;
        char c;
        while((c=getchar())<'0'||c>'9')
            if(c=='-')
                neg=-1;
        x=c-'0';
        while((c=getchar())>='0'&&c<='9')
            x=x*10+(c-'0');
        return x*neg;
    }
    int main()
    {
        int n=read(),m=read();
        for(int i=1;i<=n;i++)
            t[i]=read();
        sort(t+1,t+n+1);
        for(int i=1;i<=n;i++)
            s[i]=s[i-1]+t[i];
        memset(f,0x7f,sizeof(f));
        t[0]=-inf;
        f[0][0]=0;
        for(int i=0;i<=n;i++)
        {
            int MAX=min(m-1,t[i+1]-t[i]);
            for(int j=0;j<=MAX;j++)
                if(f[i][j]!=inf)
                    for(int k=1;i+k<=n;k++)
                    {
                        int tmp=max(t[i]+j+m-t[i+k],0);
                        f[i+k][tmp]=min(f[i+k][tmp],f[i][j]+(tmp+t[i+k])*k-(s[i+k]-s[i]));
                    }
        }
        int ans=inf;
        for(int i=0;i<m;i++)
            ans=min(ans,f[n][i]);
        printf("%d
    ",ans);
        return 0;
    }

      

  • 相关阅读:
    Linux:删除程序
    Linux:目录操作
    Linux:加载硬盘
    mysql:查询结果添加序列号
    mysql:结果集去重
    mysql:字符串转换为日期类型
    MVC:上传文件时限制文件类型
    WebApi:WebApi的Self Host模式
    WebApi:过滤器的种类
    几种知名开源富文本编辑器记录和对比(仅供参考)
  • 原文地址:https://www.cnblogs.com/xiannvzuimei/p/10011508.html
Copyright © 2011-2022 走看看