1. 朴素 DP
将每个航班看作一个状态。设 dp[i]dp[i]dp[i] 表示以第 iii 个航班作为最后一个乘坐的航班,到达其终点城市 viv_ivi 时所积累的最小总挫败感(包括在该航班到达后等待到下一航班之前的所有挫败感,但注意最后到达 nnn 时不再需要等待,所以终点可以直接统计答案)。
初始条件:城市 111 在时刻 000 可以看作一个“虚拟航班”,其到达时间为 000,终点为城市 111,且挫败感为 000。
对于航班 iii,如果我们之前乘坐的航班是 jjj,且满足 vj=uiv_j = u_ivj =ui 且 ej≤sie_j \le s_iej ≤si ,则转移为:
dp[i]=minj:vj=ui, ej≤si(dp[j]+(si−ej)2)dp[i] = \min_{j: v_j = u_i,\ e_j \le s_i} \big( dp[j] + (s_i - e_j)^2 \big) dp[i]=j:vj =ui , ej ≤si min (dp[j]+(si −ej )2)
最终答案:所有终点为 nnn 的航班 iii 的 dp[i]dp[i]dp[i] 的最小值(因为到达 nnn 后即可停止,无需再等待)。
直接枚举 jjj 是 O(m2)O(m^2)O(m2),不可行。
2. 斜率优化(凸包)
观察转移式:
dp[i]=minj(dp[j]+si2−2siej+ej2)dp[i] = \min_{j} \left( dp[j] + s_i^2 - 2s_i e_j + e_j^2 \right) dp[i]=jmin (dp[j]+si2 −2si ej +ej2 )
整理为关于 x=six = s_ix=si 的一次函数形式:
dp[i]=si2+minj((−2ej)⋅si+(dp[j]+ej2))dp[i] = s_i^2 + \min_{j} \left( (-2e_j) \cdot s_i + (dp[j] + e_j^2) \right) dp[i]=si2 +jmin ((−2ej )⋅si +(dp[j]+ej2 ))
令直线的斜率为 aj=−2eja_j = -2e_jaj =−2ej ,截距为 bj=dp[j]+ej2b_j = dp[j] + e_j^2bj =dp[j]+ej2 ,则查询时在凸包上求 x=six = s_ix=si 处的最小值,加上 si2s_i^2si2 即可。
由于 eje_jej 随 jjj 递增(按到达时间排序),斜率 aj=−2eja_j = -2e_jaj =−2ej 是单调递减的(因为 eje_jej 递增,−2ej-2e_j−2ej 递减)。同时查询的 x=six = s_ix=si 也是递增的(按起飞时间排序),因此可以使用单调队列维护凸包,查询时指针单调移动,总复杂度 O(m)O(m)O(m)。
但注意:并不是所有航班 jjj 都能立即用于转移,因为必须满足 ej≤sie_j \le s_iej ≤si 。因此我们需要按时间顺序动态添加直线:将航班按到达时间 eee 排序,处理起飞时间 sss 升序的航班时,将所有到达时间不超过当前 sss 的航班对应的直线加入其终点城市 vjv_jvj 的凸包中。
于是算法流程:
* 将航班按起飞时间升序排序(用于 DP 顺序)。
* 将航班按到达时间升序排序(用于加入凸包的顺序)。
* 维护一个指针 ppp,指向按到达时间排序的数组,当处理起飞时间 sss 时,将所有 e≤se \le se≤s 的航班加入其终点城市的凸包。
* 对每个航班 iii,在其起点城市 uiu_iui 的凸包上查询 x=six = s_ix=si 得到最小值,计算 dp[i]dp[i]dp[i]。
* 如果 vi=nv_i = nvi =n,更新答案。
3. 凸包实现细节
* 每个城市单独维护一个下凸包(因为要求最小值,且斜率单调递减)。
* 直线结构体 Line { long long a, b; }。
* 添加直线时,若新直线使队尾直线变得无用,则弹出(使用叉积判断,避免浮点数)。
* 查询时,由于斜率单调递减,查询的 xxx 单调递增,因此指针在凸包上单调移动,复杂度均摊 O(1)O(1)O(1)。
注意:初始时,城市 111 在时刻 000 有一条直线:斜率为 000(因为 e=0e=0e=0),截距为 000(dp=0dp=0dp=0),表示从城市 111 出发无需等待。
4. 时间复杂度
* 排序 O(mlogm)O(m \log m)O(mlogm)。
* DP 遍历每个航班 O(m)O(m)O(m),每个航班加入一次凸包,查询一次凸包,总均摊 O(m)O(m)O(m)。
* 总复杂度 O(mlogm)O(m \log m)O(mlogm),可通过。
易错点
* 凸包维护时需注意斜率单调性及查询指针的正确性。
* 由于存在自环(ui=viu_i = v_iui =vi )或起点等于终点的情况,转移时需正确处理。
* 初始直线应加入城市 111 的凸包。
* 答案可能很大,使用 long long,上限设为 (1LL<<62)。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
OK直接放代码