CF-1445 C - Division 数论,质因数,唯一分解定理

题意

给定一个 \(p (p\le 10^{18})\), 一个 \(q(q \le 10^9)\), 要找到一个最大的 \(x\) 满足:

  1. \(p \%x = 0\)
  2. \(q \% x \neq 0\)

分析

直接枚举 \(p\) 的因数不可取,复杂度为 \(O(\sqrt p)\)。需要另辟蹊径。

容易发现,若 \(p\%q \neq 0\) ,那么答案即为 \(p\)

接下来考虑 \(p\%q = 0\) 的情况。

考虑到唯一分解的定理对于任意一个大于 1 的数字 n 都有

\[n = q_1^{c_1}q_2^{c_2}\cdots q_n^{c_n} \]

其中 \(q_i\)\(n\) 的质因数,\(c_i\) 为其指数。

如果一个整数 \(n\) 不能被 \(m\) 整除,那么肯定有一个质数 \(e\),它在 \(n\) 中的指数小于在 \(m\) 中的指数。例如 \(12 = 2^2*3^1\)\(8 = 2^3 * 3^0\)

然后我们枚举这个 \(e\),它必定是 \(q\) 的一个质因数,所以我们枚举 \(q\) 的质因子 \(e\),然后不断的让 \(p\) 除以 \(e\),直到 \(p\%q\neq 0\),此时的 \(p\) 就是满足题目要求的 \(x\),最后在所有的情况中取一个最大的 \(x\) 即可。

单组询问复杂度 \(O(\sqrt q)\)

int T;
ll p, q;

ll gcd(ll a, ll b){
    return b == 0 ? a : gcd(b, a % b);
}
void solve(ll t){
    ll res = 0;
    // 枚举 q 的质因数
    for(int i = 2; i * i <= t;i++){
        if(t % i) continue;
        ll now = p; // 尝试不断的用 i 去除 p, 直到 p % q != 0
        while(now % q == 0) now /= i;
        while(t % i == 0) t /= i; 
        res = max(res, now);
    }
    if(t > 1){ // 质因数分解的最后一步
        ll now = p;
        while(now % q == 0) now /= t;
        res = max(res, now);
    }
    printf("%lld\n", res);
}
int main(){
    cin >> T;
    while(T--){
        scanf("%lld%lld", &p, &q);
        if(p % q == 0) {
            solve(q);
        } else {
            printf("%lld\n", p);
        }
    }
    return 0;
}

贴一下官方题解,原理与上述一致。

posted @ 2020-11-10 21:37  kpole  阅读(235)  评论(0编辑  收藏  举报