E. Divisor Paths
time limit per test
3 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a positive integer DD. Let's build the following graph from it:
- each vertex is a divisor of DD (not necessarily prime, 11 and DD itself are also included);
- two vertices xx and yy (x>yx>y) have an undirected edge between them if xx is divisible by yy and xyxy is a prime;
- the weight of an edge is the number of divisors of xx that are not divisors of yy.
For example, here is the graph for D=12D=12:
Edge (4,12)(4,12) has weight 33 because 1212 has divisors [1,2,3,4,6,12][1,2,3,4,6,12] and 44 has divisors [1,2,4][1,2,4]. Thus, there are 33 divisors of 1212 that are not divisors of 44 — [3,6,12][3,6,12].
There is no edge between 33 and 22 because 33 is not divisible by 22. There is no edge between 1212 and 33 because 123=4123=4 is not a prime.
Let the length of the path between some vertices vv and uu in the graph be the total weight of edges on it. For example, path [(1,2),(2,6),(6,12),(12,4),(4,2),(2,6)][(1,2),(2,6),(6,12),(12,4),(4,2),(2,6)] has length 1+2+2+3+1+2=111+2+2+3+1+2=11. The empty path has length 00.
So the shortest path between two vertices vv and uu is the path that has the minimal possible length.
Two paths aa and bb are different if there is either a different number of edges in them or there is a position ii such that aiai and bibi are different edges.
You are given qq queries of the following form:
- vv uu — calculate the number of the shortest paths between vertices vv and uu.
The answer for each query might be large so print it modulo 998244353998244353.
Input
The first line contains a single integer DD (1≤D≤10151≤D≤1015) — the number the graph is built from.
The second line contains a single integer qq (1≤q≤3⋅1051≤q≤3⋅105) — the number of queries.
Each of the next qq lines contains two integers vv and uu (1≤v,u≤D1≤v,u≤D). It is guaranteed that DD is divisible by both vv and uu (both vv and uu are divisors of DD).
Output
Print qq integers — for each query output the number of the shortest paths between the two given vertices modulo 998244353998244353.
Examples
input
Copy
12 3 4 4 12 1 3 4
output
Copy
1 3 1
input
Copy
1 1 1 1
output
Copy
1
input
Copy
288807105787200 4 46 482955026400 12556830686400 897 414 12556830686400 4443186242880 325
output
Copy
547558588 277147129 457421435 702277623
Note
In the first example:
- The first query is only the empty path — length 00;
- The second query are paths [(12,4),(4,2),(2,1)][(12,4),(4,2),(2,1)] (length 3+1+1=53+1+1=5), [(12,6),(6,2),(2,1)][(12,6),(6,2),(2,1)] (length 2+2+1=52+2+1=5) and [(12,6),(6,3),(3,1)][(12,6),(6,3),(3,1)] (length 2+2+1=52+2+1=5).
- The third query is only the path [(3,1),(1,2),(2,4)][(3,1),(1,2),(2,4)] (length 1+1+1=31+1+1=3).
题意:给定一个D,然后构造出一个图。这个图的点为D的因子,对于任意两个点(U,V),若UV之商为一个质数,那么存在一条边,边权为 属于U的因子但不属于V的因子的数的个数。Q次询问,每次询问两个点UV,问U到V之间的最短路径的数量。
分析:显然图中的点的个数很少,为D的因子个数,大概是log级别的。对于一条边,从U到V,想当于对U乘或除一个质数,那么显而易见,对于一对UV,U是V的因子,那么从V到U的最短路径必然是只做除法的路径。再来观察一下路径长度的含义。若两条边相连,那么必然有其中一个点是另外一个点的因子,那么实际上边权=V的因子数-U因子数,再引进与U相连的点Q,UQ边权=U的因子数-Q的因子数,那么有V-Q的权值=V的因子数-Q的因子数,说明两点之间,若其中一个是另一个因子,那么他们的最短路径一定是不断除以任意一个质因子,权值为因子数之差,那么方案数即为从将(A/B)不断除以质因子直到1的方案数。经典的组合数问题,答案为(A/B)的质因子幂之和的阶乘 除以 质因子幂的阶乘之积。显然复杂度是可以接受的。
现在得到了其中一点是另一点的因子的解决方法,那么若两点没有整除关系,则需要先由一点到一个中间数,再由这个中间数到另外一点,这个中间数显然就是他们的GCD。
#include <bits/stdc++.h>
using namespace std;
const int mod = 998244353;
long long fac[100004];
void init() {
fac[0] = 1;
for (int i = 1; i < 100004; ++i) {
fac[i] = fac[i - 1] * i % mod;
}
}
long long qk(long long a, long long n) {
long long res = 1;
while (n) {
if (n & 1)res = res * a % mod;
a = a * a % mod;
n >>= 1;
}
return res;
}
long long cal(long long a) {
vector<int> v;
v.clear();
for (long long i = 2; i * i <= a; ++i) {
int num = 0;
while (a % i == 0) {
a /= i;
num++;
}
if (num)v.push_back(num);
}
if (a != 1)v.push_back(1);
long long res = 1;
long long ans = 0;
for (auto it:v) {
res = res * qk(fac[it], mod - 2) % mod;
ans += it;
}
res = res * fac[ans] % mod;
return res;
}
unordered_map<long long, long long> mp;
int main() {
long long d;
cin >> d;
int q;
cin >> q;
init();
for (long long i = 1; i * i <= d; ++i) {
if (d % i == 0) {
mp[i] = cal(i);
mp[d / i] = cal(d / i);
}
}
while (q--) {
long long u, v;
scanf("%lld%lld", &u, &v);
long long g = __gcd(u, v);
long long ans = mp[u / g] * mp[v / g] % mod;
printf("%lld\n", ans);
}
}