ABC342E Last Train题解

思路

文章题意很复杂,大概归纳一下:
每一个从 A i A_i Ai B i B_i Bi 的火车的发车时刻都是等差数列:
l i , l i + d i , l i + 2 d i ⋯ l i + ( k i − 1 ) d i l_i,l_i+d_i,l_i+2d_i\cdots l_i+(k_i-1)d_i li,li+di,li+2dili+(ki1)di
每辆车都要花 c i c_i ci 的时间到达 B i B_i Bi
这很明显就是一个有向图,也没有负环,合适用Dijkstra。
我们把每条边的方向反一反。
不过,每条边的边权并不是一个固定的数值。
假设如今正在遍历第 i i i 条边,此时的 f ( B i ) f(B_i) f(Bi) 是已知的,要通过 f ( B i ) f(B_i) f(Bi) 来松弛 f ( A i ) f(A_i) f(Ai)

例如样例1中的 3 3 3 号车站,发现经过它的列车时刻表为:


这时,表格右侧标橙的三辆列车正好衔接上了。
在第一次列车从 l i l_i li 发车后,要不晚于 f ( B i ) f(B_i) f(Bi) 时刻到达 B i B_i Bi ,意味着不晚于发车后 f ( B i ) − l i − c i f(B_i) -l_i-c_i f(Bi)lici 时刻乘上火车,乘坐第 ⌊ f ( B i ) − l i − c i d i ⌋ \lfloor \frac{f(B_i) -l_i-c_i}{d_i}\rfloor dif(Bi)lici (编号从 0 0 0 开始) 辆火车出发。
注意:当 f ( B i ) − l i − c i < 0 f(B_i) -l_i-c_i<0 f(Bi)lici<0 时,说明此时的最晚出发时间已经早于首班车,则乘不上车。
所以有以下递推式:
f ( A i ) = ⌊ f ( B i ) − l i − c i d i ⌋ d i + l i f(A_i)=\lfloor \frac{f(B_i) -l_i-c_i}{d_i}\rfloor d_i+l_i f(Ai)=dif(Bi)licidi+li

易错点

  1. ⌊ f ( B i ) − l i − c i d i ⌋ \lfloor \frac{f(B_i) -l_i-c_i}{d_i}\rfloor dif(Bi)lici 并不等于c++中的
(arri[now] - g[now][i].l - g[now][i].c) / g[now][i].d;

除法并不完全是下取整
2.最短路中,除了节点编号,其它变量要记得开long long。

代码

void dijkstra(){
    priority_queue<pair<long long,int> > pq;
    pq.push(make_pair(inf,n));
    while(!pq.empty()){
        int now = pq.top().second;
        long long v = pq.top().first;
        pq.pop();
        if(vis[now] == true)    continue;
        arri[now] = v;
        vis[now] = true;
        for(int i = 0;i < g[now].size();i ++){
            if(vis[g[now][i].b] == false){
                long long num;
                if(v == inf) num = g[now][i].k - 1;
                else{
                    if(arri[now] - g[now][i].l - g[now][i].c < 0)   continue;
                    num = (arri[now] - g[now][i].l - g[now][i].c) / g[now][i].d;
                    num = mmin(num,g[now][i].k - 1);
                }
                long long cal = g[now][i].l + 1LL * num * g[now][i].d;
                if(cal > arri[g[now][i].b]){
                    arri[g[now][i].b] = cal;
                    pq.push(make_pair(cal,g[now][i].b));
                }
            }
        }
    }
}
  • 17
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值