CF 1334 E. Divisor Paths (思维、数论)

题目:传送门

题意

给你一个整数D,有一个无向图,图的节点为 D 的因子,若 x % y == 0 && x / y 是一个质数,则节点 x 和 y 有一条无向边,边权为 是 x 的因子但不是 y 的因子的数的个数。有 q 次询问,每次询问输入两个节点 x、y 问节点 x 到节点 y 边权最小的路径有多少条,输出答案对 998244353 取模后的结果。

1 <= D <= 10^15; 1 <= q <= 3*10^5 ;  1 <= x,y <= D

思路

沿着图移动,就是当前点移动到当前点乘以某个质数或者除以某个质数。

从 x 到 y 的所有最短路径都经过 gcd(x, y)

答案就是 从 x 移动到 gcd(x, y) 的最短路径条数 乘以 从 y 移动到 gcd(x, y) 的最短路劲的条数。

从 x 移动到 gcd(x, y) 的最短路径,就是 x 除以 x/gcd(x,y) 的质因子,除的顺序可以随意,那就是求 x/gcd(x,y) 的质因子,然后求一个 多重集合的组合,就是 x 到 gcd(x,y) 最短路径条数。

从 y 移动到 gcd(x, y) 同理。

#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned long long
#define mem(i, j) memset(i, j, sizeof(i))
#define rep(i, j, k) for(int i = j; i <= k; i++)
#define dep(i, j, k) for(int i = k; i >= j; i--)
#define pb push_back
#define make make_pair
#define INF INT_MAX
#define inf LLONG_MAX
#define PI acos(-1)
#define fir first
#define sec second
#define lb(x) ((x) & (-(x)))
using namespace std;

const int N = 1e6 + 5;
const LL mod = 998244353;

LL ksm(LL a, LL b) {
    LL ans = 1LL;
    while(b) {
        if(b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans;
}

LL D;
LL fac[105], ifac[105];
LL pre[105], tot;

void init() {

    fac[0] = 1LL;
    rep(i, 1, 99) fac[i] = fac[i - 1] * i % mod;
    ifac[99] = ksm(fac[99], mod - 2);
    dep(i, 0, 98) ifac[i] = ifac[i + 1] * (i + 1) % mod;

    for(LL i = 2; i * i <= D; i++) {
        if(D % i == 0) {
            pre[++tot] = i;
            while(D % i == 0) D /= i;
        }
    }
    if(D > 1) pre[++tot] = D;
}

void solve() {
    LL x, y;
    scanf("%lld %lld", &x, &y);

    int c1 = 0, c2 = 0;
    LL ans = 1LL;

    rep(i, 1, tot) {
        int c = 0;
        while(x % pre[i] == 0) {
            x /= pre[i];
            c++;
        }
        while(y % pre[i] == 0) {
            y /= pre[i];
            c--;
        }

        if(c > 0) {
            c1 += c;
            ans = ans * ifac[c] % mod;
        }
        else {
            c2 -= c;
            ans = ans * ifac[-c] % mod;
        }
    }
    ans = ans * fac[c1] % mod * fac[c2] % mod;
    printf("%lld\n", ans);
}

int main() {

    scanf("%lld", &D);
    init();


    int _; scanf("%d", &_);
    while(_--) solve();

//    solve();

    return 0;
}

猜你喜欢

转载自www.cnblogs.com/Willems/p/12685133.html