解题思路
记 为与 距离不超过 的最左、最右岛屿,包含 本身。两数组单调不减,可用双指针求出。
最短路径严格递增。否则删除一个局部极值点后,相邻两点距离仍不超过 ,与路径最短矛盾。
从 连续跳向最右可达岛屿,记第 次跳跃后为 。在 及其右侧,至多跳跃 次可到达的岛屿恰好构成 ,所以最短路径第 层位于 ,不同层严格分离。
考虑两条不同最短路径。每层分别取较小、较大的岛屿,仍构成合法路径;从某层较大点跳向下一层较小点也合法,因为距离只会缩短。若至少两层不同,在这两层之间从较大路径切换到较小路径,就得到第三条路径。因此,恰好两条最短路径仅在一层不同。该层的两个点必须相邻,否则夹在中间的点也能替换,产生第三条路径。
设分叉点为 ,共同前驱、后继为 。可作 到 中间点的区间为 ,故恰好有:
记 为满足以下条件的左端点 的数量,包含 :从 到 的最短路径唯一;连续向最右岛屿跳跃,在最短路径长度对应的次数后恰好到达 。
设最后一次跳跃前为 ,有 。 时直接贡献 ; 时,设上一层最右可达点为 ,由 可知 ,故本层可能的前驱恰为 。唯一性要求 ,且此前路径唯一。令 ,由 ,得到:
减去的 对应已经统计的 。对称定义 ,统计最短路径唯一,且从 向最左连续跳跃恰好到达 的右端点 ,包含 。令 ,得到:
两式分别从左向右、从右向左计算。
固定分叉 。若左端点在 左侧, 必须为该层最右可达点,而能飞往 的前驱恰为 ,故必须有 。反之,这一条件把两条分支的前驱都强制为 。右侧同理:若终点在 右侧,必须且仅须 ,将分叉后的共同点强制为 。
令 为命题 的指示函数。包含不延伸的情况,两侧权值为:
这些限制同时保证最短性:左侧贪心链先到达 ,再到达 ;右侧发生延伸时,下一步恰好到达 。结合 的定义,剩余距离无法缩短。反向同理,所以两侧唯一段之间恰好保留 两个选择,权值可以独立相乘。
按 汇总左侧,再枚举 ,答案为:
每对双径岛屿仅有一个分叉位置,因此不会重复统计。时间复杂度 ,空间复杂度 。
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=2000005;
ll x[N];
int l[N],r[N],f[N],s[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;
}
r[i]=j;
s[i]=0;
}
l[n+1]=n+1;
for(int i=1;i<=n;i++)
{
f[i]=1+min(i,l[i+1])-l[i];
if(l[i]<i&&r[l[i]]==i)f[i]+=f[l[i]]-1;
if(r[i]>i+1)s[r[i]-1]+=l[r[i]-1]==i?f[i]:1;
}
r[0]=0;
ll ans=0;
for(int i=n;i>=1;i--)
{
f[i]=1+r[i]-max(i,r[i-1]);
if(r[i]>i&&l[r[i]]==i)f[i]+=f[r[i]]-1;
if(l[i]<i-1)ans+=1ll*s[l[i]]*(r[l[i]+1]==i?f[i]:1);
}
cout<<ans<<'\n';
}
return 0;
}