P1315 观光公交 - 贪心
Posted dprswdr
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P1315 观光公交 - 贪心相关的知识,希望对你有一定的参考价值。
k=0时,直接模拟...
k=1时,找指向下车乘客最多的站的边,使用加速器。
k>1时,我们枚举每个加速器,类似上一问的做法,暴力找一遍影响最大的边,然后更新答案。
令g[i]表示边i所能影响到的最远的站。
当 到达站i+1的时间>=站i+1晚到达的人的到达时间时,即到达站i+1时可以直接前往站i+2,则在边i使用加速器是有意义的。
则边i能影响到的站为边i+1能影响到的最远的站。
反之,当到达站i+1时仍需等待最晚的人上车,说明在边i使用加速器与不使用没什么区别。
此时,则边i能影响到的站就是站i+1。
最后我们枚举每一条边,看在站i~g[i]下车人数最多的边i是那一条,就在这一条边使用加速器。
我们可以用前缀和sum[g[i]]-sum[i]来加速判断。
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int N=1000+100,M=10000+100; int d[N];//连接站i与站i+1的边i的边权 int sum[N];//站1~i下车人数之和 int lst[N];//站i最后一个到达的人的到达时间 int ari[N];//站i的到达时间 int g[N];//在边i使用加速器所能够影响到的最远的站g[i] int tim[M],fro[M],to[M];//乘客i到达时间 乘客i从站fro[i]出发 去往站to[i] //数组别开小了!!! int main(){ int n,m,k; scanf("%d%d%d",&n,&m,&k); for(int i=1;i<n;i++){ scanf("%d",&d[i]); } for(int i=1;i<=m;i++){ scanf("%d%d%d",&tim[i],&fro[i],&to[i]); sum[to[i]]++; lst[fro[i]]=max(lst[fro[i]],tim[i]); } for(int i=1;i<=n;i++) sum[i]+=sum[i-1]; ari[1]=0; for(int i=2;i<=n;i++){ ari[i]=max(ari[i-1],lst[i-1])+d[i-1]; //计算到达每个站的时间 } int ans=0; for(int i=1;i<=m;i++){ ans+=ari[to[i]]-tim[i]; //计算不使用加速器时最初的答案 } //O(nk) 暴力使用每个加速器 while(k--){ g[n-1]=n;//在边n-1使用加速器所能够影响的最远的站为站n for(int i=n-2;i;i--){ if(ari[i+1]>lst[i+1]) g[i]=g[i+1]; //如果刚到站i+1即可前往下一个站; //说明在边i使用加速器所能影响到的最远的点相当于在边i+1使用加速器所能影响到的最远的点 else g[i]=i+1; //若到达站i+1后仍需等待乘客上车,说明在边i使用加速器无意义。 } //暴力找影响最大的边 int res=-1,pos=0; for(int i=1;i<n;i++){ if(d[i]&&sum[g[i]]-sum[i]>res){ res=sum[g[i]]-sum[i]; pos=i; } } if(res==-1) break; //说明无法再使用加速器 d[pos]--; ans-=res; //使用一个加速器,每一个车上乘客的到达时间减1,即答案减去车上乘客的数量 for(int i=2;i<=n;i++){ ari[i]=max(ari[i-1],lst[i-1])+d[i-1]; //重新计算使用加速器后到达每个站的时间 } } printf("%d",ans); return 0; }
以上是关于P1315 观光公交 - 贪心的主要内容,如果未能解决你的问题,请参考以下文章