题目传送门
题意
一个图,你从 1 1 1 号点出发,求到 n n n 号点的最短路。
对于每个点,有一个初始高度,每个单位时间会变化某个定值。
对于一条边 ( i , j ) (i,j) (i,j),当 h i = h j {h_i}={h_j} hi=hj 时,才可以从 i i i 走到 j j j。
思路
最短路很明显可以用 dijkstra 解决,我们考虑高度如何处理。
一条边 ( i , j ) (i,j) (i,j),当 ( l i + s i ) ≡ ( l j + s j ) ( m o d H ) ({l_i}+{s_i}) \equiv ({l_j}+{s_j}) \pmod H (li+si)≡(lj+sj)(modH) 时满足要求。
为满足题目要求,我们设在 x x x 秒时 l i = l j l_i=l_j li=lj。
∴ l i + x × S i ≡ l j + x × S j ( m o d H ) \therefore l_i + x \times S_i \equiv l_j + x \times S_j \pmod H ∴li+x×Si≡lj+x×Sj(modH)。
∴ l i + x × S i + y × H = l j + x × S j \therefore l_i + x \times S_i + y \times H = l_j + x \times S_j ∴li+x×Si+y×H=lj+x×Sj。
∴ x × ( S i − S j ) + y × H = l j − l i \therefore x \times (S_i - S_j) + y \times H = l_j - l_i ∴x×(Si−Sj)+y×H=lj−li。
然后我们就可以用 exgcd 求了,这里讲一下 exgcd 的执行过程。
首先求出一组解 x 0 , y 0 x_0 , y_0 x0,y0,设 k = g c d ( S i − S j , H ) k = gcd(S_i - S_j,H) k=gcd(Si−Sj,H)。
那么我们就可以求出通解 x = x 0 + m × H k , y = y 0 + m × H k x = x_0 + m \times \dfrac{H}{k} ,y = y_0 + m \times \dfrac{H}{k} x=x0+m×kH,y=y0+m×kH,其中 m m m 为一个整数。
那么当 x > d i s u x > dis_u x>disu 时,即可通过,然后就可以求出最快的可通过的时刻。
代码
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
inline int read(){
int x=0,f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
return x*f;
}
inline void write(int x){
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
const int maxn=2e5+5;
int t,n,m,h;
int a[maxn],l[maxn],s[maxn],d[maxn],v[maxn];
vector<int> g[maxn];
struct node{
int now,dis;
bool operator<(node x) const{
return x.dis<dis;
}
};
int exgcd(int a,int b,int &x,int &y){
if(!b) return x=1,y=0,a;
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
void solve(){
n=read(),m=read(),h=read();
for(int i=1;i<=n;i++) g[i].clear(),d[i]=2e18,v[i]=0;
for(int i=1;i<=n;i++) l[i]=read();
for(int i=1;i<=n;i++) s[i]=read();
for(int i=1,u,v;i<=m;i++) u=read(),v=read(),g[u].push_back(v),g[v].push_back(u);
priority_queue<node> q;
q.push({1,0}),d[1]=0;
while(q.size()){
int f=q.top().now;
q.pop();
if(v[f]) continue;
v[f]=1;
for(auto i:g[f]){
int w,x,y,g=exgcd((s[f]-s[i]+h)%h,h,x,y),t;
if((l[i]-l[f])%g!=0) continue;
x=x*(l[i]-l[f])/g,t=abs(h/g),x=(x%t+t)%t;
if(d[f]>x) x=x+(d[f]-x+t-1)/t*t;
if(d[i]>x+1) d[i]=x+1,q.push({i,d[i]});
}
}
if(d[n]>=2e18) cout<<-1<<endl;
else cout<<d[n]<<endl;
}
signed main(){
t=read();
while(t--) solve();
return 0;
}