Hankson的趣味题
链接: [link]https://www.luogu.com.cn/problem/P1072
题目:
Hanks 博士是 BT(Bio-Tech,生物技术)领域的知名专家,他的儿子名叫 Hankson。
现在,刚刚放学回家的 Hankson 正在思考一个有趣的问题。
今天在课堂上,老师讲解了如何求两个正整数 c1 和 c2 的最大公约数和最小公倍数。
现在 Hankson 认为自己已经熟练地掌握了这些知识,他开始思考一个“求公约数”和“求公倍数”之类问题的“逆问题”,这个问题是这样的:
已知正整数 a0,a1,b0,b1,设某未知正整数 x 满足:
1.x 和 a0 的最大公约数是 a1;
2.x 和 b0 的最小公倍数是 b1。
Hankson 的“逆问题”就是求出满足条件的正整数 x。
但稍加思索之后,他发现这样的 x 并不唯一,甚至可能不存在。
因此他转而开始考虑如何求解满足条件的 x 的个数。
输入格式
输入第一行为一个正整数 n,表示有 n 组输入数据。
接下来的 n 行每行一组输入数据,为四个正整数 a0,a1,b0,b1,每两个整数之间用一个空格隔开。
输入数据保证 a0 能被 a1 整除,b1 能被 b0 整除。
输出格式
输出共 n 行。
每组输入数据的输出结果占一行,为一个整数。
对于每组数据:若不存在这样的 x,请输出 0;
若存在这样的 x,请输出满足条件的 x 的个数;
数据范围
1≤n≤2000,
1≤a0,a1,b0,b1≤2∗10^9
题意:
给出四个数a0,a1,b0,b1。一个整数x,使得gcd(a0,x)=a1,lcm(b0,x)=b1,求满足这个条件的x的个数
思路:
因为x和b0的最小公倍数b1,所以x一定是b的约数,我们最开始想到的方法就是找出b1的所有的约数,然后一个个去判断是否符合条件,在这里如果我们采用试除法的话,时间复杂度是n√b1=2000√21e9≈1e8,就有可能有组数据会超时,所以我们可以换种做法,我们可以把1~√b1间所有的质数筛选出来,然后再dfs一遍,把b1的所有的质因子留下,这样时间复杂度大约是n√b1/log(b1)≈1e7,最后在跑一遍,判断一下即可。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=1e5+10;
typedef long long ll;
int prim[N],cnt=0;
bool vis[N];
int h[1600],d=0,ct; //h 数组来存符合条件的质数
struct node{
int num,p;
}f[16]; //f 来存 1~√b1间的所有素数 num 为质数 p为个数
void prime() {
vis[0] = vis[1] = true;
memset(vis,0,sizeof vis);
for (int i = 2; i <= N; i++) {
if (!vis[i]) prim[cnt++] = i;
for (int j = 0; i * prim[j] < N; j++) { //线性筛求质数
vis[i * prim[j]] = true;
if (i % prim[j] == 0) break;
}
}
}
int gcd(int a,int b) {
return b ? gcd(b, a % b) : a;
}
void dfs(int u,int x) {
if (u == ct) {
h[d++] = x;
return;
}
for (int i = 0; i <= f[u].p; i++) {
dfs(u + 1, x);
x *= f[u].num;
}
}
int main() {
prime();
int t;
cin >> t;
while (t--) {
int a, b, c,e;
ct = 0;
cin >> a >> b >> c >> e;
int k=e;
for (int i = 0; prim[i] * prim[i] <= k; i++) {
int p = prim[i];
if (k % p == 0) {
int s = 0;
while (k % p == 0) k /= p, s++;
f[ct++] = {p, s};
}
}
if (k > 1) f[ct++] = {k, 1};
d = 0;
dfs(0, 1);
int res = 0;
for (int i = 0; i < d; i++) {
int u = h[i];
if (gcd(u, a) == b && (ll) c *u / gcd(u, c) == e) res++;
}
cout << res << '\n';
}
return 0;
}