D. Friendly Spiders

D. Friendly Spiders

Mars is home to an unusual species of spiders — Binary spiders.

Right now, Martian scientists are observing a colony of $n$ spiders, the $i$-th of which has $a_i$ legs.

Some of the spiders are friends with each other. Namely, the $i$-th and $j$-th spiders are friends if $\gcd(a_i, a_j) \ne 1$, i. e., there is some integer $k \ge 2$ such that $a_i$ and $a_j$ are simultaneously divided by $k$ without a remainder. Here $\gcd(x, y)$ denotes the greatest common divisor (GCD) of integers $x$ and $y$.

Scientists have discovered that spiders can send messages. If two spiders are friends, then they can transmit a message directly in one second. Otherwise, the spider must pass the message to his friend, who in turn must pass the message to his friend, and so on until the message reaches the recipient.

Let's look at an example.

Suppose a spider with eight legs wants to send a message to a spider with $15$ legs. He can't do it directly, because $\gcd(8, 15) = 1$. But he can send a message through the spider with six legs because $\gcd(8, 6) = 2$ and $\gcd(6, 15) = 3$. Thus, the message will arrive in two seconds.

Right now, scientists are observing how the $s$-th spider wants to send a message to the $t$-th spider. The researchers have a hypothesis that spiders always transmit messages optimally. For this reason, scientists would need a program that could calculate the minimum time to send a message and also deduce one of the optimal routes.

Input

The first line of input contains an integer $n$ ($2 \le n \le 3\cdot10^5$) — the number of spiders in the colony.

The second line of input contains $n$ integers $a_1, a_2, \ldots, a_n$ ($1 \le a_i \le 3\cdot10^5$) — the number of legs the spiders have.

The third line of input contains two integers $s$ and $t$ ($1 \le s, t \le n$) —the spiders between which the message must be sent.

Output

If it is impossible to transmit a message between the given pair of spiders, print $-1$.

Otherwise, in the first line of the output print the integer $t$ ($t \ge 1$) — the number of spiders that participate in the message transmission (i. e. the minimum time of message delivery in seconds plus one). In the second line, print $t$ different integers $b_1, b_2, \ldots, b_t$ ($1 \le b_i \le n$) — the ids of the spiders through which the message should follow, in order from sender to receiver.

If there are several optimal routes for the message, output any of them.

Examples

input

7
2 14 9 6 8 15 11
5 6

output

3
5 4 6 

input

7
2 14 9 6 8 15 11
5 7

output

-1

input

7
2 14 9 6 8 15 11
5 5

output

1
5

Note

The first example is shown above. It shows that the message from the $5$-th spider (with eight legs) to the $6$-th spider (with $15$ legs) is optimal to pass through the $4$-th spider (with six legs).

In the second example, the spider number $7$ (with $11$ legs) is not friends with anyone, so it is impossible to send him a message.

 

解题思路

  题意大概就是如果两个数的最大公约数不为$1$,那么就在这两个数间连一条边。如果直接按照定义来建图那么时间复杂度和空间复杂度都是$O(n^2)$,必然超时。突破口是在值域上,$a_i \leq 3 \times {10}^5$,意味着我们可以尝试从值域的角度去建图。实际上官方给出的建图方法还是很难想到的(反正我是不可能想到的),看完后只能用妙来形容。

  创建一个二分图,其中左边部分由$n$个$a_i$构成,右边部分由所有不超过$3 \times {10}^5$(或者不超过$\max\limits_{1 \leq i \leq n} {a_i}$)的质数构成。遍历左边部分的每一个点,对于左边部分的某一个点$a_i$对其进行质因数分解,在右边部分找到所有$a_i$的质因子并各自与$a_i$连一条边。

  下面分析时间复杂度,假设$m = \max\limits_{1 \leq i \leq n} {a_i}$,建图的流程是先筛出所有不超过$m$的质数,这部分的时间复杂度为$O(m)$。

  然后是分解质因数,如果直接暴力分解质因数那么时间复杂度为$O(n \sqrt{m})$,最大可以达到${10}^8$级别,很可能会超时。因此在筛质数的过程中顺便求出每个数的最小质因子,在分解质因数的过程中就可以根据最小质因子来试除,时间复杂度就变成了$O(n \log{m})$。

  然后试根据质因子来连边,首先因为有$2 \times 3 \times 5 \times 7  \times 11 \times 13 = 30030 < 3 \times {10}^5$,所有在不超过$3 \times {10}^5$的数中,一个数最多有$6$个不同的质因子,因此建边的时间复杂度为$O(2 \cdot 6 \cdot n) \approx O(n \log{m})$,空间复杂度为$O(12 \cdot n)$。

  最后是点数的问题,二分图左边部分有$n$个点,右边部分的节点个数取决于不超过$m$的质数的个数,因此总的节点个数最多不会超过$n + m$个(实际上不超过$3 \times {10}^5$的质数有$25998$个),其中右边部分的节点编号从$n+1$开始。

  建完图然后就是求最短路了,根据题意可设所有边的权值均为$1$,因此可以跑个$\text{bfs}$,时间复杂度为$O(n + m + n \log{m})$。最后答案就是从起点到终点距离的一半,即答案要除以$2$(实际上就是减去所有从右边部分到左边部分的边的权值)。当然也可设从左到右的边的权值为$1$,从右到左的边的权值为$0$,然后跑个$\text{0-1bfs}$。

  AC代码如下:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 3e5 + 10, M = 6e5 + 10, K = 36e5 + 10;
 5 
 6 int n, src, dest;
 7 int a[N];
 8 int head[M], e[K], ne[K], idx;
 9 int primes[N], minp[N], cnt;
10 bool vis[N];
11 int id[N];
12 int q[M], hh, tt = -1;
13 int dist[M], path[M];
14 
15 void add(int v, int w) {
16     e[idx] = w, ne[idx] = head[v], head[v] = idx++;
17 }
18 
19 void get_prime(int m) {
20     for (int i = 2; i <= m; i++) {
21         if (!vis[i]) {
22             primes[cnt++] = i;
23             minp[i] = i;
24             id[i] = n + cnt;    // 右边部分的节点编号从n+1开始
25         }
26         for (int j = 0; primes[j] <= m / i; j++) {
27             vis[primes[j] * i] = true;
28             minp[primes[j] * i] = primes[j];
29             if (i % primes[j] == 0) break;
30         }
31     }
32 }
33 
34 bool bfs() {
35     if (src == dest) return true;
36     q[++tt] = src;
37     memset(dist, 0x3f, sizeof(dist));
38     dist[src] = 0;
39     while (hh <= tt) {
40         int t = q[hh++];
41         for (int i = head[t]; i != -1; i = ne[i]) {
42             if (dist[e[i]] > dist[t] + 1) {
43                 dist[e[i]] = dist[t] + 1;
44                 path[e[i]] = t;
45                 if (e[i] == dest) return true;
46                 q[++tt] = e[i];
47             }
48         }
49     }
50     return false;
51 }
52 
53 int main() {
54     scanf("%d", &n);
55     for (int i = 1; i <= n; i++) {
56         scanf("%d", a + i);
57     }
58     get_prime(*max_element(a + 1, a + n + 1));    // 筛出不超过max(a[1~n])的质数
59     memset(head, -1, sizeof(head));
60     for (int i = 1; i <= n; i++) {
61         int x = a[i];
62         while (x > 1) {    // 分解质因数
63             int t = minp[x];
64             add(i, id[t]), add(id[t], i);    // 右边部分的质因子t与a[i]连一条无向边
65             while (x % t == 0) {
66                 x /= t;
67             }
68         }
69     }
70     scanf("%d %d", &src, &dest);
71     if (bfs()) {    // 有解
72         vector<int> stk;
73         while (dest) {    // 求最短路径的具体方案
74             if (dest <= n) stk.push_back(dest);    // 路径中不应该包含右边部分的点
75             dest = path[dest];
76         }
77         printf("%d\n", stk.size());
78         reverse(stk.begin(), stk.end());
79         for (auto &x : stk) {
80             printf("%d ", x);
81         }
82     }
83     else {    // 无解
84         printf("-1");
85     }
86     
87     return 0;
88 }

  一点总结。

  如果发现有$n$个点可以两两互相到达,比如所有$2$的倍数$2,\ 4,\ 6\ \ldots$,如果每两个点都建一条权值为$1$的边的话时间复杂度和空间复杂度都是$O(n^2)$。这题就给出了一种新的建图方式,可以开个虚点,其他点到虚点的边的权值为$1$,从虚点到其他点的权值为$0$,一样可以达到同样的效果,而时间复杂度和空间复杂度都变成了$O(n)$,如下图:

  其中这里的虚点因为这$n$个点的共同关系而把这$n$个点连接起来,在这道题这$n$个点的共同关系就是都有同一个质因数$x$,而虚点就是二分图右边部分的质数$x$。

  更新:参考Minimum Reverse Operations所带来的启发,这里再提供另外一种做法。

  在bfs时最重要的问题是每个节点会与大量的节点有边相连,因此在枚举所有的边时会导致超时。而根据bfs的性质,如果一个节点已经被更新了,那么到这个节点的最小距离就已经确定了,之后不会再被更新。因此在枚举相邻节点时很多节点都是无用节点(不会再被更新)。

  为此这里参考这道题目的做法,先给每一个质数开一个哈希表,用来存储含有该质因子的数所对应的下标。那么在bfs时要枚举数$x$能到达的相邻节点时,先对$x$进行质因数分解,然后对于每个不同的质因子在对应的哈希表中存在的节点进行更新,并将更新过的节点从所有哈希表中删除。

  AC代码如下,时间复杂度为$O(n + n \log{M})$:

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 3e5 + 10;
 5 
 6 int n, src, dest;
 7 int a[N];
 8 int primes[N], cnt;
 9 bool vis[N];
10 int minp[N];
11 unordered_set<int> st[N];
12 vector<int> fs[N];
13 int dist[N], path[N];
14 int q[N], hh, tt = -1;
15 
16 void get_prime(int n) {
17     for (int i = 2; i <= n; i++) {
18         if (!vis[i]) {
19             primes[cnt++] = i;
20             minp[i] = i;
21         }
22         for (int j = 0; primes[j] <= n / i; j++) {
23             vis[primes[j] * i] = true;
24             minp[primes[j] * i] = primes[j];
25             if (i % primes[j] == 0) break;
26         }
27     }
28 }
29 
30 int main() {
31     int n;
32     scanf("%d", &n);
33     for (int i = 1; i <= n; i++) {
34         scanf("%d", a + i);
35     }
36     scanf("%d %d", &src, &dest);
37     get_prime(*max_element(a + 1, a + n + 1));
38     for (int i = 1; i <= n; i++) {
39         int t = a[i];
40         while (t != 1) {
41             int p = minp[t];
42             if (i != src) st[p].insert(i);
43             fs[i].push_back(p);
44             while (t % p == 0) {
45                 t /= p;
46             }
47         }
48     }
49     memset(dist, 0x3f, sizeof(dist));
50     dist[src] = 0;
51     q[++tt] = src;
52     while (hh <= tt) {
53         int t = q[hh++];
54         for (auto &x : fs[t]) {
55             auto it = st[x].begin();
56             while (it != st[x].end()) {
57                 int c = *it;
58                 dist[c] = dist[t] + 1;
59                 path[c] = t;
60                 q[++tt] = c;
61                 auto p = next(it);
62                 for (auto &x : fs[c]) {
63                     st[x].erase(c);
64                 }
65                 it = p;
66             }
67         }
68     }
69     if (dist[dest] == 0x3f3f3f3f) {
70         printf("-1");
71     }
72     else {
73         printf("%d\n", dist[dest] + 1);
74         vector<int> ans;
75         while (dest) {
76             ans.push_back(dest);
77             dest = path[dest];
78         }
79         reverse(ans.begin(), ans.end());
80         for (auto &x : ans) {
81             printf("%d ", x);
82         }
83     }
84     
85     return 0;
86 }

 

参考资料

  Codeforces Round #843 (Div. 2) Editorial:https://codeforces.com/blog/entry/111286

  Codeforces Round #843 (Div. 2) D(数学+图论) E(结论):https://zhuanlan.zhihu.com/p/598085405

posted @ 2023-01-17 18:14  onlyblues  阅读(110)  评论(0编辑  收藏  举报
Web Analytics