解题思路
假设在第i站使用加速器:
1、 假设观光车到达i+1站的时间小于以i+1站为起点的乘客到达i+1站最晚的时间,说明该观光车到达i+1站之后要等待这位乘客到达之后才会出发;若在i站使用加速器,观光车到达i+1站的时间会变短,使在i+1站下车的乘客的花费时间变短,但是观光车到达i+1站之后仍然要等待这位最晚到达的乘客上车之后才能出发,所以这个加速器的最大有效范围只到i+1站。
2、 假设观光车到达i+1的时间等于以i+1站为起点的乘客到达i+1站最晚的时间,说明该观光车到达i+1站之后等无需等待,直接出发;若在i站使用加速器,观光车到达i+1站的时间会变短,使在i+1站下车的乘客的花费时间变短,但是观光车到达i+1站之后仍然要等待这位最晚到达的乘客上车之后才能出发,所以这个加速器的最大有效范围只到i+1站。
3、 假设观光车到达i+1的时间大于以i+1站为起点的乘客到达i+1站最晚的时间,说明观光车到达i+1车站之后无需等待,直接出发;若在i站使用加速器,则加速器的效果会延续到之后的若干站,则在第i站使用加速器的最大有效范围等于在第i+1站使用加速器的最大有效范围。
发现,在i加速,假设影响范围边界在j(i小于j)那么,在i+1~j下车的乘客,都可以获得加速。显然,i以及之前下车的乘客已经毫无关系了。
至于j+1之后的下车的乘客也不可以了,因为到达j之后,加速已经不能影响到后面了。说明,这次加速之后,一定到达j的时间,比j最后一个人到达的时间要晚。也就是说,到达j之后,目的地在j+1之后的乘客,只能继续等待。不论再怎么加速,还是没有用。所以,这一部分也不会节省总时间。
所以,减少的时间就是i+1~j区间下车乘客的人数了。
AC_Code
python
n,m,k = [int(i) for i in input().split()]
d = [int(i) for i in input().split()]
N = 1005
tim = [0 for _ in range(N*10)]
st = [0 for _ in range(N*10)]
nd = [0 for _ in range(N*10)]
las = [0 for _ in range(N)]
sum = [0 for _ in range(N)]
go = [0 for _ in range(N)]
rang = [0 for _ in range(N)]
tot = 0
for i in range(m):
tim[i],st[i],nd[i] = [int(i) for i in input().split()]
st[i], nd[i] = st[i]-1,nd[i]-1
las[st[i]] = max(las[st[i]],tim[i])
sum[nd[i]] +=1
go[0] = 0
for i in range(1,n):
sum[i]+=sum[i-1]
go[i]=max(go[i-1],las[i-1])+d[i-1]
for i in range(m):
#print(go[nd[i]] - tim[i])
tot += go[nd[i]] - tim[i]
while k:
k-=1
rang[n-2] = n-1
for i in range(n-3,-1,-1):
if go[i+1]<=las[i+1]:
rang[i] = i + 1
else:
rang[i] = rang[i + 1]
mx = 0
id = 0
for i in range(n-1):
now = sum[rang[i]]-sum[i]
if mx<now and d[i]:
mx = now
id = i
if mx == 0:
break
tot -= mx
d[id]-= 1
for i in range(id,rang[id]+1):
go[i]=max(go[i-1],las[i-1])+d[i-1]
print(tot)
c++
#include<bits/stdc++.h>
using namespace std;
const int N=1005;
int n,m,k;
int rang[N],d[N],las[N],sum[N];//影响范围,i~i+1长度,i点最后人,前缀和
int st[10*N],nd[10*N],tim[10*N];//每个人
int go[N];//到i时间
int tot;//总时间
int main(){
scanf("%d%d%d",&n,&m,&k);
for(int i=1;i<=n-1;i++){
scanf("%d",&d[i]);
}
for(int i=1;i<=m;i++){
scanf("%d%d%d",&tim[i],&st[i],&nd[i]);
las[st[i]]=max(las[st[i]],tim[i]);
sum[nd[i]]++;
}
go[1]=0;
for(int i=2;i<=n;i++) sum[i]+=sum[i-1],go[i]=max(go[i-1],las[i-1])+d[i-1];
for(int i=1;i<=m;i++){
tot+=go[nd[i]]-tim[i];
}
while(k){
k--;
rang[n-1]=n;
for(int i=n-2;i>=1;i--){//更新影响范围
if(go[i+1]<=las[i+1]){
rang[i]=i+1;
}
else rang[i]=rang[i+1];
}
int mx=0,id=0;
for(int i=1;i<=n-1;i++){//找最优解
int now=sum[rang[i]]-sum[i];
if(mx<now&&d[i]){
mx=now,id=i;
}
}
//这里可以特判mx==0 break 但是其实没什么优化
tot-=mx;d[id]--;
for(int i=id+1;i<=rang[i];i++) //最后进行修改,注意循环的范围
go[i]=max(go[i-1],las[i-1])+d[i-1];
}
printf("%d",tot);
return 0;
}