https://www.luogu.org/problem/show?pid=1315
这是一题贪心题
首先在不放加速器的时候所有乘客的旅行时间总和是一定的。。。
因为每个站的出发时间一定是本站最后一位乘客上车时间(好吧不一定也有可能最后一名到了车还没到。。。)
所以应该是
max(本站最后一位乘客上车时间,车到站时间)
我们需要合理地安排加速器使所有乘客的旅行时间总和最小
那么这个加速器啊就得放得恰到好处
也就是说使这个加速器效果最好,能减少旅行时间最多
于是我们可以找出各站之间的乘坐人数,可以O(n)时间内推出
for(int i=n;i>1;i--)if(d[i-1]){
s[i-1]=b[i];
if(t[i]>a[i])s[i-1]+=s[i];
}else s[i-1]=0;
其中s[i]表示乘坐人数,b[i]表示在i站下车人数,t[i]表示该站发车最晚时间,d[i]表示相邻两站距离
于是问题就转化成找中间站人数多的对答案贡献大的一段放加速器
那我们就可以直接贪心啦!!!
当然啦这个站放了加速器一定要有效果。。。比如说你不放加速器到站时间是4,然而最后一位乘客上车时间是6,这时你放了加速器就是浪费。。。
这个也是需要考虑到的
最后答案就是在最优加速器方案时所有乘客的旅行时间总和
那么怎么高效的算这个东西呢?
我们一开始输入时做一个预处理:
for(int i=1;i<=m;i++){
int tt,aa,bb;
scanf("%d%d%d",&tt,&aa,&bb);
b[bb]++;
ans-=tt;
a[aa]=max(a[aa],tt);
}
你可能已经注意到了这个减掉tt的ans,为什么这个ans一开始要减去到站时间呢?
我们接着看最后统计答案时候的代码:
for(int i=1;i<=n;i++)ans+=t[i]*b[i];
最后这里的t[i]是已经被加速器优化后的最迟到站时间
这里的t[i]*b[i]代表的意义是在i站点下车花费t[i]时间车从1号站出现到抵达本站乘上本站下车人数
(可能“出现”这个词用得不好,但其他我也想不出什么比这个词好的了,原谅我语文差)
这样一来,前后ans抵消掉一部分以后其实就是每位乘客的旅行时间呀
其实就是差分啦~。。。
这个应该很好理解吧
那么这题就被很好地解决了啊
ps:为什么我这个东西速度这么慢。。。人家好像几十毫秒解决了的我总时间用了3000+ms。。。
据说人家用的好像有递推。。。
没事能过就行啦
#include<bits/stdc++.h>
using namespace std;
int d[100001],a[100001],b[100001],t[100001],s[100001],ans=0;
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++){
int tt,aa,bb;
scanf("%d%d%d",&tt,&aa,&bb);
b[bb]++;ans-=tt;
a[aa]=max(a[aa],tt);
}
while(k--){
memset(s,0,sizeof s);
for(int i=2;i<=n;i++)t[i]=max(t[i-1],a[i-1])+d[i-1];
for(int i=n;i>1;i--)if(d[i-1]){
s[i-1]=b[i];
if(t[i]>a[i])s[i-1]+=s[i];
}else s[i-1]=0;
int ma=0,maa=-1;
for(int i=1;i<n;i++)if(ma<s[i])ma=s[i],maa=i;
if(maa==-1)break;
d[maa]--;
}
for(int i=2;i<=n;i++)t[i]=max(t[i-1],a[i-1])+d[i-1];
for(int i=1;i<=n;i++)ans+=t[i]*b[i];
printf("%d",ans);
return 0;
}