P1315 观光公交
题解
贪心大法好啊
思路:
先计算出不加速的时候的时间
然后考虑在哪里加速
用一开始的时间不断减就好啦
先考虑不加速:
由于人到达车站的时间是不会改变的
所以每个车站的出发时间是不会改变的
就是:start[ i ] = max(last[ i ] , arrive[ i ])
arrive[ i+1 ] = start[ i-1 ] + d[ i ]
所以最后累加每个人的QWQ得到最初答案
然后考虑往哪里加??
(1)如果你到达这个站点 i 的时候,最后一名乘客还没来
也就是车等人,就没有必要加速了,因为对后面的站点无影响,而且加了也没大有用
(2)如果是人等车,还是可以考虑考虑的
可能会对后面的站点造成影响
车每到达一个站点,就会有一部分人上车,一部分人下车
(不排除没人上下车的可能吧,不知道数据)
然后这些人就会产生等待时间和乘车时间,对答案产生影响
所以我们就找到站点中影响人数最多的那个,对ta加速就好了
sum[ i ] 前缀和维护到达站点i及之前站点的总人数
yx[ i ] (yingxiang影响)记录站点i可以影响到的最大站点编号
so,sum[ yx[ i ] ] - sum[ i ] 就是可以影响到的最多人数
这样人数多的就要放加速器
贪心就是这里
接下来枚举,一个一个找要放加速器的位置
每次使用加速器后站点的影响可能会发生改变,因此每次重算
然后寻找影响最大的站点,缩短路程,ans更新
然后更新arrive&start
最后输出答案
代码
#include<bits/stdc++.h> using namespace std; inline int read() { int ans=0; char last=' ',ch=getchar(); while(ch<'0'||ch>'9') last=ch,ch=getchar(); while(ch>='0'&&ch<='9') ans=ans*10+ch-'0',ch=getchar(); if(last=='-') ans=-ans; return ans; } const int maxn=1010,maxm=10010; int n,m,k; int d[maxn],arrive[maxn],start[maxn],last[maxn],yx[maxn],sum[maxn]; int ans,maxx=-1; struct node { int u,v,w; }peo[maxm]; void chuli(int x) { while(x) { --x; int goal; //要加速的站点编号 maxx=-1; //最大影响人数 yx[n-1]=yx[n]=n; for(int i=n-2;i>=1;i--) { if(arrive[i+1]<=last[i+1]) yx[i]=i+1; //车等人,最多对后一个点产生影响 else yx[i]=yx[i+1]; //人等车 } for(int i=1;i<n;i++) //枚举可能使用加速器的站点(肯定不用考虑 { int kk=sum[yx[i]]-sum[i]; if(kk>maxx&&d[i]>0) { maxx=kk; goal=i; } } ans-=maxx; //人数即加速的时间 d[goal]--; for(int i=1;i<=n;i++) //更新arrive&start { start[i]=max(last[i],arrive[i]); arrive[i+1]=start[i]+d[i]; } } return ; } int main() { n=read();m=read();k=read(); for(int i=1;i<n;i++) d[i]=read(); for(int i=1;i<=m;i++) { peo[i].w =read(); peo[i].u =read(); peo[i].v =read(); sum[peo[i].v]++; //到站人数 last[peo[i].u]=max(last[peo[i].u],peo[i].w ); } arrive[1]=0; for(int i=1;i<=n;i++) { sum[i]+=sum[i-1]; start[i]=max(last[i],arrive[i]); arrive[i+1]=start[i]+d[i]; } for(int i=1;i<=m;i++) { ans+=(arrive[peo[i].v]-peo[i].w); } chuli(k); printf("%d ",ans); return 0; }