设 P=x0*a、Q=x0*b 后可化成 a*b=y0/x0 且 gcd(a,b)=1,答案就是 y0/x0 的不同质因子个数对应的 2^k。
OJ: luogu
题目 ID: P1029
难度:普及-
标签:数论最大公约数质因数分解python
日期: 2026-06-18 22:24
题意
给出两个正整数
要求统计有多少组正整数有序对 (P,Q) 满足:
思路
先看一个可以直接验证想法的朴素解:
把题目改写成:
那么只要枚举 (a,b),检查它们是否互质,就能数出答案。
cpp
// brute.cpp:小数据暴力解,用来帮助理解题意并辅助对拍。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll x0, yv;
ll gcd_ll(ll a, ll b) {
while (b != 0) {
ll t = a % b;
a = b;
b = t;
}
return a;
}
void solve() {
if (yv % x0 != 0) {
cout << 0 << '\n';
return;
}
ll n = yv / x0;
ll ans = 0;
for (ll a = 1; a * a <= n; a++) {
if (n % a != 0) {
continue;
}
ll b = n / a;
if (gcd_ll(a, b) == 1) {
if (a == b) {
ans += 1;
} else {
ans += 2;
}
}
}
cout << ans << '\n';
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> x0 >> yv;
solve();
return 0;
}这个想法已经很接近正解了,关键只差最后一步:
既然要求 a 和 b。
例如若:
那么方案只会是下面四种:
2^2 去向 |
5 去向 |
a |
b |
|---|---|---|---|
| 左边 | 左边 | 20 |
1 |
| 左边 | 右边 | 4 |
5 |
| 右边 | 左边 | 5 |
4 |
| 右边 | 右边 | 1 |
20 |
表格里每个“质因子块”都只有两种去向:给左边或给右边。
所以如果 n 有 k 个不同质因子,总方案数就是:
2^k
于是正式做法就很简单:
- 先判断
y0是否能被x0整除; - 令
; - 对
n做试除分解; - 每发现一个新的不同质因子,就让答案乘
2。
Python 知识
- Python 整数不会溢出,可以直接计算质因子块数量对应的
1 << k。 while quotient % prime == 0一次除尽同一质因子,只统计不同质因子个数。- 位移
1 << distinct_primes就是,准确表达每个质因子块的二选一。 - 先检查整除关系,避免对不可能的输入继续分解。
/home/rainboy/mycode/hugo-blog/content/program_language/python/cpp_to_python_pitfalls.md:Python 任意精度整数。/home/rainboy/mycode/hugo-blog/content/program_language/python/map_reduce_filter.md:把独立选择归约成乘积的思路。
代码
python
import sys
gcd_value, lcm_value = map(int, sys.stdin.buffer.read().split())
if lcm_value % gcd_value:
print(0)
else:
quotient = lcm_value // gcd_value
distinct_primes = 0
prime = 2
while prime * prime <= quotient:
if quotient % prime == 0:
distinct_primes += 1
while quotient % prime == 0:
quotient //= prime
prime += 1
if quotient > 1:
distinct_primes += 1
print(1 << distinct_primes)复杂度
设
总结
这题表面在数 (P,Q),本质在数 y0/x0 的不同质因子块如何分给左右两边。
把 gcd 和 lcm 先拆开之后,问题会一下子变成很标准的数论计数题。