G. Moving Platforms

G. Moving Platforms

There is a game where you need to move through a labyrinth. The labyrinth consists of n platforms, connected by m passages.

Each platform is at some level li, an integer number from 0 to H1. In a single step, if you are currently on platform i, you can stay on it, or move to another platform j. To move to platform j they have to be connected by the passage, and their levels have to be the same, namely li=lj.

After each step, the levels of all platforms change. The new level of platform i is calculated as li=(li+si)modH, for all i.

You start on platform 1. Find the minimum number of steps you need to get to platform n.

Input

The first line of input contains a single integer t (1t104) — the number of test cases. Then the descriptions of the test cases follow.

The first line of each test case contains three integers n, m, and H (2n105, 1m105, 1H109).

The second line contains n integers li, the initial level of each platform (0liH1).

The third line contains n integers si, the change of level for each platform (0siH1).

Next m lines contain a description of the passages. Each passage is described as a pair of integers — the platforms, connected by the passage. There is at most one passage connecting each pair of platforms, and there is no passage connecting a platform to itself.

The sum of n for all tests does not exceed 105, the sum of m for all tests does not exceed 105.

Output

For each test case, print a single integer, the minimum number of steps needed to get from platform 1 to platform n.

If it is impossible to get to platform n, print 1.

Example

input

3
3 3 10
1 9 4
2 3 0
1 2
3 2
1 3
2 1 10
1 2
4 6
1 2
8 7 25
22 14 5 3 10 14 11 1
9 5 4 10 7 16 18 18
2 8
6 3
3 5
7 5
2 6
1 4
4 7

output

6
-1
52

Note

This is how levels of the platforms change, and what actions we need to perform in the first example.

  Platform 1 Platform 2 Platform 3 Action
Step 1 1 9 4 Stay on the platform 1
Step 2 3 2 4 Stay on the platform 1
Step 3 5 5 4 Move to the platform 2
Step 4 7 8 4 Stay on the platform 2
Step 5 9 1 4 Stay on the platform 2
Step 6 1 4 4 Move to the platform 3

 

解题思路

  前置知识:扩展欧几里得算法用于求解 ax+by=gcd(a,b) 的可行解。对于任意方程 ax+by=m 存在可行解的充要条件是 gcd(a,b)m,如果有解则先通过 exgcd 求出 ax+by=gcd(a,b) 的一组可行解 x0y0,那么 x0=mgcd(a,b)x0y0=mgcd(a,b)y0 就是 ax+by=m 的一组可行解。得到可行解后就可以构造通解 {x=x0+kbgcd(a,b)y=y0kagcd(a,b),其中 kZ

  相邻两点 uv 只有在高度相同时的时刻才能从 u 走到 v,假设到达 u 的时刻为 distu,现在要求满足 lu+suxlv+svx(modH) 且大于等于 distu 的最小时刻 x。该同余方程等价于 (susv)x+Hy=lvlu,yZsusv 相当于 aH 相当于 blvlu 相当于 m。为了方便如果 a<0,则令 a(amodH+H)modH,即把 a 变成模 H 意义下最小的非负整数,同余方程仍然成立,同理 bm

  令 d=gcd(susv,H),先求出 (susv)x+Hy=d 的可行解 x0,那么 x0=lvludx0 就是 (susv)x+Hy=lvlu 的可行解,令 z=kd,那么 x=x0+kz 就是通解。接着求满足 xdistu 的最小 x,如果 x0=distu 那么直接有 x=x0。否则如果 x0>distu,那么需要 x0kzdistu,k0,等价于 kx0distuzk 取等号即可,则 x=x0+x0distuzz。同理如果 x0<distu,那么需要 x0+kzdistu,k0,等价于 kdistux0zk 取等号,则 x=x0+distux0zz

  以上就是求每个相邻节点边权的做法,然后就可以用 Dijkstra 跑最短路了。简单证明一下正确性,假设当前未标记的节点中 distu 最小,那么不可能再通过其他未标记的节点 v 来更新使得 distu 变小,因为 dist_vdist_u 而从 vu 的最小时刻 xdistv,所以与一般的 Dijkstra 一样标记 u 并更新其他未标记节点的最小值即可。

  AC 代码如下,时间复杂度为 O(mlogH+mlogm)

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 1e5 + 10, M = N * 2;

int h[N], e[M], ne[M], idx;
int a[N], b[N];
LL dist[N];
bool vis[N];

void add(int u, int v) {
    e[idx] = v, ne[idx] = h[u], h[u] = idx++;
}

int exgcd(int a, int b, int &x, int &y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}

void solve() {
    int n, m, k;
    scanf("%d %d %d", &n, &m, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d", a + i);
    }
    for (int i = 1; i <= n; i++) {
        scanf("%d", b + i);
    }
    memset(h, -1, n + 10 << 2);
    idx = 0;
    while (m--) {
        int u, v;
        scanf("%d %d", &u, &v);
        add(u, v), add(v, u);
    }
    priority_queue<array<LL, 2>> pq;
    pq.push({0, 1});
    memset(dist, 0x3f, n + 10 << 3);
    dist[1] = 0;
    memset(vis, 0, n + 10);
    while (!pq.empty()) {
        auto p = pq.top();
        pq.pop();
        if (vis[p[1]]) continue;
        vis[p[1]] = true;
        for (int i = h[p[1]]; i != -1; i = ne[i]) {
            int x, y;
            int d = exgcd((b[p[1]] - b[e[i]] + k) % k, k, x, y);
            if ((a[e[i]] - a[p[1]]) % d) continue;
            LL t = LL(a[e[i]] - a[p[1]] + k) % k / d * x;
            LL z = k / d;
            if (t > -p[0]) t -= (t + p[0]) / z * z;
            else if (t < -p[0]) t += (-p[0] - t + z - 1) / z * z;
            if (dist[e[i]] > t + 1) {
                dist[e[i]] = t + 1;
                pq.push({-t - 1, e[i]});
            }
        }
    }
    printf("%lld\n", dist[n] == 0x3f3f3f3f3f3f3f3f ? -1 : dist[n]);
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
        solve();
    }
    
    return 0;
}

 

参考资料

  Codeforces Round 927 (Div. 3) A-G:https://zhuanlan.zhihu.com/p/682734505

posted @   onlyblues  阅读(42)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2023-02-20 构造新矩阵
Web Analytics
点击右上角即可分享
微信分享提示