风景迷人的小城Y市,拥有n个美丽的景点。由于慕名而来的游客越来越多,Y市特意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0分钟出现在1号景点,随后依次前往2、3、4……n号景点。从第i号景点开到第i+1号景点需要Di分钟。任意时刻,公交车只能往前开,或在景点处等待。
设共有m个游客,每位游客需要乘车1次从一个景点到达另一个景点,第i位游客在Ti分钟来到景点Ai,希望乘车前往景点Bi(Ai 一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司机ZZ给公交车安装了k个氮气加速器,每使用一个加速器,可以使其中一个Di减1。对于同一个Di可以重复使用加速器,但是必须保证使用后Di大于等于0。 那么ZZ该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
第1行是3个整数n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数和氮气加速器个数。
第2行是n-1个整数,每两个整数之间用一个空格隔开,第i个数表示从第i个景点开往第i+1个景点所需要的时间,即Di。
第3行至m+2行每行3个整数Ti, Ai, Bi,每两个整数之间用一个空格隔开。第i+2行表示第i位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
共一行,包含一个整数,表示最小的总旅行时间。
3 3 2 1 4 0 1 3 1 1 2 5 2 3
10
1s
样例说明:
对D2使用2个加速器,从2号景点到3号景点时间变为2分钟。
公交车在第1分钟从1号景点出发,第2分钟到达2号景点,第5分钟从2号景点出发,第7分钟到达3号景点。
第1个旅客旅行时间7 - 0 = 7分钟;
第2个旅客旅行时间2 - 1 = 1分钟;
第3个旅客旅行时间7 - 5 = 2分钟。
总时间7 + 1 + 2 = 10分钟。
数据范围:
对于10%的数据,k = 0;
对于20%的数据,k = 1;
对于40%的数据,2 ≤ n ≤ 50,1 ≤ m ≤ 1,000,0 ≤ k ≤ 20,0 ≤ Di ≤ 10,0 ≤ Ti ≤ 500;
对于60%的数据,1 ≤ n ≤ 100,1 ≤ m ≤ 1,000,0 ≤ k ≤ 100,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 10,000;
对于100%的数据,1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000,0 ≤ k ≤ 100,000,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 100,000。
分析
每个人在车上的时间 等于 车到达目的站的时间 减去 这个人到达起始站的时间
由于人到达起始站的时间题目给出不会变化
所以求解一个最优的车到达目的站的时间即可
假设到达第i+1站的时间是time[i]
从前往后逐个求解到站时间
可以得出time[i] = max{time[i-1], last[i]} + d[i]
其中last[i]为从第i站上车的旅客中最后到达的一个到达的时间 可以用O(n+m)的时间预处理得出
d[i]为从i走到i+1所用的时间
很明显的 我们可以利用这个递推关系式用O(n)的时间求解time[i]
当我们令d[i]减少1时
time[1..i-1]不会变化
time[i]会减少1
考虑time[i+1]
由前面的式子得出time[i+1] = max{time[i], last[i+1]} + d[i+1]
若我们令d[i]减少之前 存在time[i] > last[i+1]则time[i+1]会减少1 否则time[i+1]就会不变
若time[i+1]减少了1 我们可以用同样的方法判断time[i+2]直到最后是否变化
若time[i+1]不变 则time[i+2]及之后的time值都不会变化
**所以 当我们令某个d[i]减少1时 从time[i]开始会有一段区间的time值均减少1
这个区间的左端为i 我们令右端为range[i]
对于j属于从i+1到range[i] 均存在time[j-1] > last[j] 且对于range[i]+1不存在time[j-1] > last[j]
说到这里 大家应该发现求解range[i]的方法了
若range[i+1] = t 则对于从i+2到t前不等式均成立且对于t+1不成立
所以我们求解range[i]只需判断对于i+1前不等式是否成立即可
若成立则 range[i] = range[i+1] 不成立则 range[i] = i
若我们修改每个值所减少的时间为reduce[i] 则reduce[i] = v[i] + v[i+1] + ... + v[range[i]]
v[i]表示到达第i+1个车站的人的数量
很明显的 reduce[i] = v[i] + reduce[i+1] 或 v[i]
现在 我们可以用O(n)的时间求解reduce了
然后每次选择一个令reduce[i]最大的i 令d[i]减少即可
注意每次修改d[i]之后 要重新计算新的time[i]
时间复杂度O(kn)
program bus;
const
mamx=10001;
maxf=1001;
var a,b,t:array[0..maxm] of longint;
right,s,ina,off,get,leave,d:array[0..maxf+1] of longint;
p,c,n,m,k,i,j,maxk,maxi,temp:longint;
reducenum:longint;
function max(q,p:longint):longint;
begin
if q>p then exit(q);
exit(p);
end;
function min(q,p:longint):longint;
begin
if q>p then exit(p);
exit(q);
end;
begin
read(n,m,k);
for i:=1 to n-1 do read(D[i]);
for i:=1 to m do
begin
read(t[i],a[i],b[i]);
inc(off[b[i]]);
leave[a[i]]:=max(leave[a[i]],t[i]);
end;
for i:=2 to n do
get[i]:=max(leave[i-1],get[i-1])+D[i-1];
p:=1;
for i:=1 to n do
begin
while((p
right[i]:=p;
end;
for i:=1 to n do
s[i]:=s[i-1]+off[i];
while k>0 do
begin
maxk:=0;
for i:=1 to n-1 do
if (s[right[i]]-s[i]>maxk)and(d[i]>0)
then begin
maxk:=s[right[i]]-s[i];
maxi:=i;
end;
if maxk=0
then break
else begin
temp:=maxlongint;
j:=maxi+1;
while(j
temp:=min(get[j]-leave[j],temp);
inc(j);
end;
temp:=min(D[maxi],temp);
temp:=min(k,temp);
dec(k,temp);
dec(D[maxi],temp);
for j:=maxi+1 to right[i] do
get[j]:=max(get[j-1],leave[j-1])+D[j-1];
p:=maxi;
c:=off[maxi];
for j:=maxi to right[i]-1 do
begin
while((p
break;
right[j]:=p;
end;
end;
end;
get[1]:=leave[1];
get[n]:=max(get[n],leave[n]);
for i:=1 to m do
inc(reducenum,get[b[i]]-t[i]);
writeln(reducenum);
end.
答案
program bus;
var n,m,k,i,j,tt,tz,dd,da,dz,mn:longint;
a,b,c,d,mm,num,time,yx:array[0..10000] of longint;
ans:longint;
function max(q,p:longint):longint;
begin
if q>p then exit(q);
exit(p);
end;
function min(q,p:longint):longint;
begin
if q>p then exit(p);
exit(q);
end;
function sum(q,p:longint):longint;
var i,ans:longint;
begin
ans:=0;
for i:=p+1 to q do
inc(ans,num[i]);
exit(ans);
end;
begin
assign(input,'bus.in');reset(input);
assign(output,'bus.out');rewrite(output);
readln(n,m,k);
for i:=1 to n-1 do read(d[i]); //记录从i站到达i+1站所用时间
for i:=1 to m do //记录每个人旅行的信息
begin
readln(a[i],b[i],c[i]);
if mm[b[i]] //统计最后一个从b[i]站上车的时间
inc(num[c[i]]); //统计从c[i]站下车的人数
end;
while true do
begin
time[1]:=0;
for i:=2 to n do //递推到达i站的时间
time[i]:=max(time[i-1],mm[i-1])+d[i-1];
yx[n]:=n; //判断修改i到i+1所用时间影响的范围
for i:=n-1 downto 1 do
begin
yx[i]:=yx[i+1];
if time[i+1]<=mm[i+1] then yx[i]:=i+1;
end;
tt:=1;
while (d[tt]=0)and(tt<=n-1) do
inc(tt);
if(tt=n)or(k=0)then break;
for i:=tt+1 to n-1 do //找出影响范围最大的(影响的人的个数)
if (d[i]<>0)and(sum(yx[tt],tt)
if sum(yx[tt],tt)=0 then break;
dd:=maxlongint; //减去最小的time[i]-mm[i],使后面不会出现mm[i]>time[i]的情况
for i:=tt+1 to yx[tt]-1 do
dd:=min(dd,time[i]-mm[i]);
dd:=min(dd,k)
dd:=min(dd,d[tt]);
k:=k-dd;
d[tt]:=d[tt]-dd;
end;
for i:=1 to m do
inc(ans,time[c[i]]-a[i]); //统计每个人旅行的时间
writeln(ans);
close(input); close(output);
end.