题解 P1315 【观光公交】
2024/6/10: 很久以前写的题解不知为什么被打回了。。
立志写一篇明明白白且老少咸宜的贪心题解
本题的思维含量特别大,蒟蒻作者和同学讨论了好几天才把这道题整明白...
首先看题。题目内容特别冗长,认真读题后,可以发现对本题的处理可分以下几个步骤:
-
读入数据
-
规划出不用氮气加速时公交车的行驶过程
-
找一段区间,使得在这个区间使用氮气加速时,能使最多的乘客旅行时间缩短;本步骤重复
k 次 -
输出答案
本题的规划过程比较复杂。现对步骤 2 进行叙述。
对于第一个景点,我们已经知道了公交车抵达第一个景点的时间(即第
那么,对于第二个景点,抵达第二个景点的时间就是离开第一个景点的时间加
假如公交车到达第
在递推到每个景点时,记录到达第
int time=0;
for(register int i=1;i<=N;++i)
{
Arrive=time;
time=max(time,Latest[i]);
time+=D[i];
}
进行完预处理,即可枚举所有的区间,并找出在每个区间使用氮气加速可以惠及多少乘客。不难发现,如果到达第
那么我们可以分情况讨论。如果
简单总结一下:如果在当前
像这样枚举每个区间后,记录惠及人数最多的区间位置。
max_num=0;
for(register int i=2;i<=N;++i)
{
if(!D[i-1]) continue;
tmp_num=0;
for(register int j=i;j<=N;++j)
{
tmp_num+=Leave[j];
if(Arrive[j]<=Latest[j]) break;
}
if(tmp_num>max_num)
{
max_num=tmp_num;
max_pos=i;
}
}
记录下位置后,便可以对
D[max_pos-1]--;
for(register int i=max_pos;i<=N;++i)
{
Arrive[i]--;
if(Arrive[i]<Latest[i]) break;
}
将以上两段操作重复
标程如下:
#include<bits/stdc++.h>
using namespace std;
int N,M,K;
struct passenger
{
int start,end;
}pas[100005];
struct station
{
int off,latest,arrive;
}sta[1005];
int Dist[1005];
int main()
{
scanf("%d%d%d",&N,&M,&K);
for(register int i=1;i<N;++i) scanf("%d",&Dist[i]);
int t;
for(register int i=1;i<=M;++i)
{
scanf("%d%d%d",&pas[i].start,&t,&pas[i].end);
sta[t].latest=max(sta[t].latest,pas[i].start);
sta[pas[i].end].off++;
}
int time=0;
for(register int i=1;i<=N;++i)
{
sta[i].arrive=time;
time=max(time,sta[i].latest);
time+=Dist[i];
}
int max_num,max_pos,tmp_num;
while(K--)
{
max_num=0;
for(register int i=2;i<=N;++i)
{
if(!Dist[i-1]) continue;
tmp_num=0;
for(register int j=i;j<=N;++j)
{
tmp_num+=sta[j].off;
if(sta[j].arrive<=sta[j].latest) break;
}
if(tmp_num>max_num)
{
max_num=tmp_num;
max_pos=i;
}
}
Dist[max_pos-1]--;
for(register int i=max_pos;i<=N;++i)
{
sta[i].arrive--;
if(sta[i].arrive<sta[i].latest) break;
}
}
int ans=0;
for(register int i=1;i<=M;++i)
ans+=sta[pas[i].end].arrive-pas[i].start;
printf("%d",ans);
return 0;
}