CF-1445 C - Division 数论,质因数,唯一分解定理
题意
给定一个 \(p (p\le 10^{18})\), 一个 \(q(q \le 10^9)\), 要找到一个最大的 \(x\) 满足:
- \(p \%x = 0\)
- \(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;
}
贴一下官方题解,原理与上述一致。
注:转载请注明出处