• Luogu P1315 观光公交 题解报告


    题目传送门

    【题目大意】

    有$n$个公交站和$m$个乘客,从第$i$个站到第$i+1$个站所需时间为$t_i$,第$i$个乘客将在时间$c_i$到达$a_i$站,在$b_i$站下车。现在有$k$个加速器,如果在$i o i+1$路段使用加速器,可以使得$t_i-1$,但要保证$t_i>0$,求所有乘客的旅行时间之和最小为多少?(每个乘客的旅行时间定义为下车的时间减去到达车站的时间)

    【思路分析】

    emmmm其实一开始没想到贪心的,我一开始还以为这会是一道DP题?(bushi)

    好吧这题的贪心策略确实有些难想,就是每次用加速器的时候要保证这个加速器可以是最多的乘客旅行时间减少。

    那么我们如何实现呢?

    先定义几个变量:

    $T[i]$表示公交车到达第$i$站的时间点,$dn[i]$记录在第$i$站下车的人数,$sum$数组记录$dn$数组的前缀和,$lst[i]$表示第$i$站最晚到达的乘客到达的时间点,$bft[i]$表示如果在$i o i+1$路段使用加速器,旅行时间减少的乘客最后下车的站点。

    然后我们明确几个转移关系:

    $T[i]=max(T[i-1],lst[i-1])+t[i]$

    $if(T[i+1]>lst[i+1]) bft[i]=bft[i+1]$

    $else bft[i]=i+1$

    对于每个加速器,我们找到一个路段使用后使得旅行时间减少的乘客最多,然后改变相应变量,再重复操作,复杂度为$O(nk)$

    【代码实现】

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<queue>
     7 #define g() getchar()
     8 #define rg register
     9 #define go(i,a,b) for(rg int i=a;i<=b;i++)
    10 #define back(i,a,b) for(rg int i=a;i>=b;i--)
    11 #define db double
    12 #define ll long long
    13 #define il inline
    14 #define pf printf
    15 #define mem(a,b) memset(a,b,sizeof(a))
    16 using namespace std;
    17 int fr(){
    18     int w=0,q=1;
    19     char ch=g();
    20     while(ch<'0'||ch>'9'){
    21         if(ch=='-') q=-1;
    22         ch=g();
    23     }
    24     while(ch>='0'&&ch<='9') w=(w<<1)+(w<<3)+ch-'0',ch=g();
    25     return w*q;
    26 }
    27 const int N=1002,M=10002;
    28 const int INF=1e9+7;
    29 int n,m,k,ans;
    30 int t[N],dn[N],lst[N],T[N],sum[N],bft[N];
    31 struct pas{
    32     int c,a,b;
    33 }p[M];
    34 int main(){
    35     //freopen("","r",stdin);
    36     //freopen("","w",stdout);
    37     n=fr();m=fr();k=fr();
    38     go(i,1,n-1) t[i]=fr();
    39     go(i,1,m){
    40         p[i]=(pas){fr(),fr(),fr()};
    41         dn[p[i].b]++;
    42         lst[p[i].a]=max(lst[p[i].a],p[i].c);
    43     }
    44     go(i,2,n) T[i]=max(T[i-1],lst[i-1])+t[i-1];
    45     go(i,1,n) sum[i]=sum[i-1]+dn[i];
    46     go(i,1,m) ans+=T[p[i].b]-p[i].c;
    47     lst[n]=INF;
    48     while(k--){
    49         rg int mx=0,id=0;
    50         back(i,n-1,1)
    51             if(T[i+1]>lst[i+1]) bft[i]=bft[i+1];
    52             else bft[i]=i+1;
    53         go(i,1,n-1)
    54             if(sum[bft[i]]-sum[i]>mx&&t[i]) mx=sum[bft[i]]-sum[i],id=i;
    55         ans-=mx;t[id]--;
    56         go(i,2,n) T[i]=max(T[i-1],lst[i-1])+t[i-1];//记得更新数组的值
    57     }
    58     pf("%d
    ",ans);
    59     return 0;
    60 }
    代码戳这里
  • 相关阅读:
    C#制作windows屏保实战
    创建一个可以修改不可以删除的文件夹或文件,windows目录和文件权限实测总结
    分享一下我用C#写的贪吃蛇和迷宫
    用C#做的汉诺塔游戏以及对汉诺塔递归的简单理解
    纪念一下即将逝去的flash,曾今的flash入门学习示例《别盯着我》C#版
    C#中关于变量的作用域不易理解的特例
    列出文件夹和遍历文件夹的区别
    怎样创建无法直接删除的文件夹--关于windows权限的迷思
    用C#写的后台整点报时工具
    用C#写差异文件备份工具
  • 原文地址:https://www.cnblogs.com/THWZF/p/11561389.html
Copyright © 2020-2023  润新知