好吧,看到这道题的题目就晕了,好长一串。。。
由于找不出来什么特别NB的算法,就上贪心吧。。。
网上看了下各种题解,对于某个车站i,如果汽车的到达i站的时间比最后一个来到第i站的时间要短的话,我们就可以考虑使用加速器了。因此枚举在哪个车站i使用加速器能够使节约的时间最多,每次使用了加速器后,更新一遍汽车到站的时间。一直不停地找最优的车站使用加速器,直到加速器用光或者用不用加速器都一样的时候就退出循环。
此种写法是一个一个地使用加速器,比较慢,但还是能过完所有点。
#include<cstdio>
#include<iostream>
#define MAXN 1005
using namespace std;
int n,m,k;
int d[MAXN],down[MAXN],last[MAXN];//到达第i+1站时间,每站下车人数,最后一个到达第i站的人
int t[10005],fr[10005],to[10005];//每个人的到站时间,起始站,终点站
int arrive[MAXN];//汽车到达第i站的时间
int main()
{
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",&t[i],&fr[i],&to[i]);
last[fr[i]] = max(last[fr[i]],t[i]);//统计到每个站的最后一个人
down[to[i]]++;//统计每站下车人数
}
arrive[1] = last[1];
while(k)
{
for(int i = 2; i <= n; i++) arrive[i] = max(arrive[i-1],last[i-1]) + d[i-1];//由于k在变化,更新汽车到达第i站的时间
int pos = 0,maxpeople = 0;//使用加速器的站点,该点使用加速器能作用的最大人数
for(int i = 1; i < n; i++)//枚举使用加速器的站点
if(d[i] > 0)
{
int temp = 0;
for(int j = i+1; j <= n; j++)
{
temp += down[j];
if(arrive[j] <= last[j]) break;//如果汽车到达j点时,还有乘客没有来或者刚来,使用加速器是对后面没有影响的
}
if(temp > maxpeople)
{
maxpeople = temp;
pos = i;
}
}
d[pos]--;
k--;
}
for(int i = 2; i <= n; i++)//更新使用了最后一个加速器后的情况
arrive[i] = max(arrive[i-1],last[i-1]) + d[i-1];
int ans = 0;
for(int i = 1; i <= m; i++)
ans += arrive[to[i]] - t[i];
printf("%d\n",ans);
}
这种写法是通过计算得到在最优的车站i使用多少个加速器能达到的最优解,由于是一堆一堆地使用加速器,比起上面那种写法要快得多。
#include<cstdio>
#include<iostream>
#define MAXN 1005
using namespace std;
int n,m,k;
int d[MAXN],down[MAXN],last[MAXN];//到达第i+1站时间,每站下车人数,最后一个到达第i站的人
int t[10005],fr[10005],to[10005];//每个人的到站时间,起始站,终点站
int sum[MAXN],arrive[MAXN],r[MAXN];//汽车到达第i站的时间,在第i站用加速器能影响到的最大站
int main()
{
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",&t[i],&fr[i],&to[i]);
last[fr[i]] = max(last[fr[i]],t[i]);//统计到每个站的最后一个人
down[to[i]]++;//统计每站下车人数
}
for(int i = 2; i <= n; i++)
arrive[i] = max(arrive[i-1],last[i-1]) + d[i-1];//统计汽车到站的时间
for(int i = 1; i <= n; i++)//统计在前i站下车的前缀和
sum[i] = sum[i-1] + down[i];
int R = 1;
for(int i = 1; i < n; i++)//计算在第i站使用加速器的影响范围
{
while((R < n&&last[R] < arrive[R])||R <= i) R++;
r[i] = R;
}
while(k)
{
int maxpeople = 0,pos = 0,maxtime = 123456789,usek;
for(int i = 1; i < n; i++)//找出使用加速器影响最大的人数
if(sum[r[i]] - sum[i] > maxpeople&&d[i] > 0)
{
maxpeople = sum[r[i]] - sum[i];
pos = i;
}
if(maxpeople == 0) break;//已经没有能影响的人了,所以再使用加速器也没用
for(int i = pos+1; i < n&&last[i] < arrive[i]; i++)//使用加速器的个数应该不超过 last[i]-arrive[i]的最小值,如果超过了,那么汽车到达i的时间就会晚于最后一个到达i的人,达不到最优解
maxtime = min(maxtime,arrive[i] - last[i]);
maxtime = min(maxtime,k);//使用加速器的限制条件
usek = min(maxtime,d[pos]);
k -= usek;
d[pos] -= usek;
for(int i = pos+1; i <= r[pos]; i++)//更新汽车到站的时间
arrive[i] = max(arrive[i-1],last[i-1])+d[i-1];
for(int i = pos,R = pos; i < r[pos]; i++)//更新使用加速器的影响范围
{
while((R < n&&last[R] < arrive[R])||R <= i) R++;
if(R >= r[i]) break;//影响范围不可能比没用的时候还大
r[i] = R;
}
}
long long ans = 0;
for(int i = 1; i <= m; i++)
ans += (long long)arrive[to[i]] - t[i];
printf("%lld\n",ans);
}