题目链接:200. Hankson的趣味题 - AcWing题库
输入样例:
2
41 1 96 288
95 1 37 1776
输出样例:
6
2
题意:问满足1.x 和 a0 的最大公约数是 a1;2.x 和 b0 的最小公倍数是 b1,的x的个数
思路:gcd(x, a0) = a1, lcm(x, b0) = b1,可以知道x是b1的因子,枚举b1的所有因子,再判断每个因子是否满足条件1、2,只不过直接从1枚举到根号b的话容易超时。
1 ∼ n中的质数个数约为 n / ln(n),
于是我们考虑将b1的质因子和他们的幂次方都处理出来,再将这些质因子dfs用不同的方式相乘组成不同的数,这些数都是b1的因子,代入条件1、2判断对错即可。
时间复杂度的判断可以参考:AcWing 200. Hankson的趣味题 - AcWing
代码:
#include<bits/stdc++.h>
#define int long long
#define pii pair<int, int>
using namespace std;
const int N = 5e4;
int pri[N], vis[N], cnt;
vector<pii> v;
vector<int> yu;
int lcm(int a, int b){
return a * b / __gcd(a, b);
}
void get_pri(int n){
for(int i = 2; i <= n; i++){
if(!vis[i]) pri[cnt++] = i;
for(int j = 0; i * pri[j] <= n; j++){
vis[i * pri[j]] = 1;
if(i % pri[j] == 0) break;
}
}
}
void dfs(int c, int p){
if(c == v.size()){
yu.push_back(p);
return;
}
for(int i = 0; i <= v[c].second; i++){
dfs(c + 1, p);
p *= v[c].first;
}
}
int32_t main(){
ios::sync_with_stdio(false);
cin.tie(0);
int tt; cin >> tt;
get_pri(45000);
while(tt--){
int a0, b0, a1, b1; cin >> a0 >> a1 >> b0 >> b1;
int d = b1;
for(int i = 0; pri[i] * pri[i] <= d; i++){
int f = 0;
while(d % pri[i] == 0){
f++;
d /= pri[i];
}
if(f) v.push_back({pri[i], f});
}
if(d > 1) v.push_back({d, 1});
dfs(0, 1);
int ans = 0;
for(int i = 0; i < yu.size(); i++){
if(__gcd(yu[i], a0) == a1 && lcm(yu[i], b0) == b1){
ans++;
}
}
printf("%lld\n", ans);
yu.clear(), v.clear();
}
}