题解:P17833 [CSP-S 2026] 迁徙
概述最短路径严格递增,恰好两条路径只能在一层经过两个相邻岛屿,其余部分唯一。双向递推统计唯一最远跳跃链的端点数,再按相邻分叉独立组合左右权值。利用最左可达点的单调性逆向恢复最右边界,并将左侧贡献化为闭式,只保留坐标、左边界与递推三个数组,时间、空间均为 O(n)。
记 li,ri 为从 i 一步可达的最左、最右岛屿,包含自身。
最短路严格递增,起点右侧各层按坐标分离。两路若至少两层不同,逐层取最大、最小路径再由大转小拼接,可得第三路;同层两点不相邻时,夹点也产生第三路。故恰好两路仅有单个相邻菱形:
p→{a,a+1}→q,p<a<a+1<q,rp=a+1,lq=a
记 fi 为到 i 的最短路唯一且每步均跳至最右可达点的起点数,包含 i;gi 为反向对称量。直接起点数与递推为:
bicifigi=min(i,li+1)−li=ri−max(i,ri−1)=1+bi+[bi>0](fli−1)=1+ci+[ci>0](gri−1)
其中 [P] 为指示函数,ln+1=n+1,r0=0;非直接起点要求前驱唯一,才可继续延伸。
固定 q,令 a=lq<q−1。此时 la+2≤a,可选前驱为 [la+1,la+2);额外左延伸仅来自 p=la=la+1。相等时,直接前驱与额外延伸恰好合成 fa+1−1,故:
sa={fa+1−1la+2−la+1la+1=lala+1>la
右延伸要求 ra+1=q,等价于 lq+1>a+1,因此:
Rq=1+[lq+1>a+1](gq−1)
两侧边界被强制后,路径最短且仅在菱形处分叉,左右独立,答案为:
A=1≤q≤nlq<q−1∑slqRq
利用 l 的单调性逆向恢复 r;逆扫时 a+1<q,可在同一数组中以 g 覆盖 f。时间、空间复杂度均为 O(n)。
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2000005;
ll x[N];
int l[N],f[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int c,T;
cin>>c>>T;
while(T--)
{
int n;
ll d;
cin>>n>>d;
for(int i=1;i<=n;i++)cin>>x[i];
int j=0;
for(int i=1;i<=n;i++)
{
while(j<n&&x[j+1]-x[i]<=d)
{
j++;
l[j]=i;
}
f[i]=1+(j>i?l[i+1]:i)-l[i];
if(f[i]>1)f[i]+=f[l[i]]-1;
}
l[n+1]=n+1;
ll ans=0;
for(int i=n;i>=1;i--)
{
int k=j;
while(l[j]==i)j--;
f[i]=1+k-max(i,j);
if(f[i]>1)f[i]+=f[k]-1;
int a=l[i];
if(a<i-1)ans+=1ll*(l[a+1]==l[a]?f[a+1]-1:l[a+2]-l[a+1])*(l[i+1]>a+1?f[i]:1);
}
cout<<ans<<'\n';
}
return 0;
}