Educational Codeforces Round 85 (Rated for Div. 2)E. Divisor Paths【数学推导】

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:

9ce70289d27adde3575a5aa840a6cc7f1d3682bb.pnguploading.4e448015.gif转存失败重新上传取消

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);
    }
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值