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;
}