zoukankan      html  css  js  c++  java
  • P1315 观光公交 贪心

     
              P1315 观光公交

    贪心

    题目链接:https://www.luogu.org/problemnew/show/1315

     

    哇,这个题贪心?好高级的贪心……完全没看出来QAQ

    看到这个题,

    刚开始想能不能dp,

    然后某大神说不满足无后效性

    首先对于每个点当然是能走就走,

    不能走就等待,这是无法控制的。

    所以只考虑氮气加速器加在哪里可以使时间总和尽量少

    后效性:

    如果选择加速,可能会使后面等待的时间更长,或者更短,对后面都会有影响。

    虽然dp不行,但是可以受启发,着这一条边加速会影响后面的所有边么?

    不一定。

    来来来,分类讨论。

    到下一个点还需要等待:以后的时间就不再影响了

    到下一个点不需要等待:对以后的时间还会加速直到……出现情况一(或者到最后一个点)!!

     即每次用加速器都会对后面的人有影响,

    用sum[i]记录到i的人数,前缀和处理,g[i]代表每个点所能影响到的最远点,

    那么sum[i + g[i]] - sum[i] 即是能影响到的人数

    这样就很容易想到选择影响尽量大的点减掉,(这里贪心)

    定义数组 :

    last[ i ] : 最后一个人到达i站点的时间。

    sum[ i ] : 到i站点的总人数。

    enter[ i ] : 公交车到i站点的最少时间(用last和enter来更新g,想想怎么更新)。

    g[ i ] : 每个站点所能影响到的最远站点,即要求的影响。

    Codes:

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int N = 20000 + 10;
    int n,m,k;
    int dis[N],last[N],g[N],enter[N];
    int ans,sum[N],maxx = -1;
    struct node{
        int time,start,end;
    }a[N];
    void init(){
        for(int i = 1;i <= m;++ i){
            last[a[i].start] = max(last[a[i].start],a[i].time);//最后一个人到a[i].start站点的时间 
            //和到这个点的时间取max 
            sum[a[i].end] ++;
        }
        enter[1] = last[1];
        for(int i = 1;i <= n;++ i){
            sum[i] += sum[i - 1];//到i站点的总人数 前缀和处理 
        }
        for(int i = 2;i <= n;++ i){
            enter[i] = max(enter[i - 1],last[i - 1]) + dis[i - 1];//公车到i站点的最少时间 
                //和最后到的时间取max 
        }
        for(int i = 1;i <= m;++ i)
            ans += enter[a[i].end] - a[i].time;//处理出不加加速器的answer,后面就可以直接减啦~ 
        return;
    }
    void work(int k){
        for(;k;-- k){
            g[n] = g[n - 1] = n;
            int tar;
            maxx = -1;
            for(int i = n - 2;i >= 1;-- i){
                if(enter[i + 1] <= last[i + 1])//下一个点如果等待 
                    g[i] = i + 1;//最多影响到下一个
                else //不等待 
                    g[i] = g[i + 1];//继续减少后面的时间 
            }
            for(int i = 1;i < n;++ i){//for边数 
                int tmp = sum[g[i]] - sum[i];//最多影响的人数 
                if(tmp > maxx && dis[i] > 0){
                    maxx = tmp;
                    tar = i;//标记最优情况减的点 
                }
            }
            ans -= maxx;//更新ans 
            dis[tar] --;//减掉dis 
            for(int i = 2;i <= n;++ i){
                enter[i] = max(enter[i - 1],last[i - 1]) + dis[i - 1];//重新更新enter 
            }
        }
        return;
    }
    int main(){
        scanf("%d%d%d",&n,&m,&k);
        for(int i = 1;i < n;++ i){
            scanf("%d",&dis[i]);
        }
        for(int i = 1;i <= m;++ i){
            scanf("%d%d%d",&a[i].time,&a[i].start,&a[i].end);
        }
        init();
        work(k);
        cout << ans << '
    ';
        return 0;
    }

     

    MAS:

    贪心真的是智商题QAQ,还是要多练吧。

  • 相关阅读:
    关于路径的小知识点
    转发与重定向
    一种反复的读写文件的方法
    文字排版reportlab
    Qgis中插件的安装位置
    spyder打开文件假死解决
    地图跳跃-超级码力
    尾部的零
    一探torch.nn究竟“What is torch.nn really?”
    KAZE特征和各向异性扩散滤波
  • 原文地址:https://www.cnblogs.com/Loizbq/p/7774761.html
Copyright © 2011-2022 走看看