Hankson的趣味题
解题思路
本题要求有多少个 x 满足 gcd(a0,x)=a1,lcm(b0,x)=b1
从 lcm(a0,x)=a1,可知 x 一定是 a1 的约数,因此我们可以用试除法求出 a1 的所有约数,注意判断是否满足这两个条件,但是这个方法的时间复杂度为 O(n√dlogd),本题的数据很大,会被卡,需要考虑进一步优化。
d 的约数个数上界大约是 1∼d,并且是远远达不到这个上界的,实际上,109 之内的自然数中,约数个数最多的自然数仅有 1536 个约数。
为了尽量避免试除法中耗费大量时间,我们可以预处理出 1∼√2\*109 之间的所有质数,然后用这些质数去将 b1 分解质因数,然后用 dfs 将分解出的所有质因数拼凑出所有的约数。
C++ 代码
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
typedef long long LL;
typedef pair<int, int> PII;
const int N = 50010;
int n;
int primes[N], cnt; //存储所有质数
bool st[N]; //记录每个数是不是合数
PII factor[N]; //存储 b1 的所有质因子及个数
int divider[N]; //记录 b1 的所有约数
int cntf, cntd;
void get_primes(int n) //线性筛法筛质数
{
for(int i = 2; i <= n; i++)
{
if(!st[i]) primes[cnt++] = i;
for(int j = 0; primes[j] <= n / i; j++)
{
st[primes[j] * i] = true;
if(i % primes[j] == 0) break;
}
}
}
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
void dfs(int u, int p) //dfs 用质因子拼凑所有约数
{
if(u == cntf)
{
divider[cntd++] = p;
return;
}
for(int i = 0; i <= factor[u].second; i++)
{
dfs(u + 1, p);
p *= factor[u].first;
}
}
int main()
{
get_primes(50000); //预处理出 1 ~ sqrt(2 * 1e9) 之间的所有质数
scanf("%d", &n);
while(n--)
{
int a0, a1, b0, b1;
scanf("%d%d%d%d", &a0, &a1, &b0, &b1);
//将 b1 分解质因子并存入 factor
int d = b1;
cntf = 0;
for(int i = 0; primes[i] <= d / primes[i]; i++)
{
int p = primes[i];
if(d % p == 0)
{
int s = 0;
while(d % p == 0) s++, d /= p;
factor[cntf++] = {p, s};
}
}
if(d > 1) factor[cntf++] = {d, 1};
//用 d1 的所有质因子拼凑出 d1 的所有约数
cntd = 0;
dfs(0, 1);
//枚举所有约数,记录满足条件的数的个数
int res = 0;
for(int i = 0; i < cntd; i++)
{
int x = divider[i];
if(gcd(x, a0) == a1 && (LL)x * b0 / gcd(x, b0) == b1) res++;
}
printf("%d\n", res);
}
return 0;
}
lcm(a0,x)=a1,gcd(b0,x)=b1 写反啦
已修正~~
if(d > 1) factor[cntf++] = {d, 1};
其实这里我不太懂,,,,d要是质数的话,前面的for循环bu不就能把本身算到吗
是这样的,在前面的循环中,我们已经把几乎全部质因子分解出来了,并且我们每分解出一个质因子,就用 d 把这个质因子除尽,因此如果将所有的质因子取出来的话,照理说这时候 d 应该除完所有的质因子,此时 d 应该是 1 才对,但是对于任意一个数 x 来说,最多只会有一个大于根号 x 的质因子,可以发现我们循环的之后,最多只会循环到 根号 d,如果我们枚举完所有小于根号 d 的质因子之后,d 还不是 1,说明 d 存在一个大于根号 d 的质因子,由于我们每找到一个质因子就用 d 把他除掉,因此最后剩下的这个 d 本身就是那个唯一一个质因子
我知道了,看错了
还有就是,我不太看得懂这个搜索,佬,能讲讲嘛QAQ
搜索就是拼凑法,我们已经将 d 分解出了所有质因子,那么这些质因子相乘凑出的所有的乘积就都是 d 的约数,我们就是依次枚举每个约数 c,然后枚举用几个 c 来拼乘积,假设 d 分解出了 x 个 c,那么 0 个 c 相乘一直到 x 个 c 相乘它都会是 d 的约数,我们就是将所有的约数都靠质因子之间的不同的搭配来拼凑出来,只要枚举完所有质因子各用多少个,然后乘在一起,整个就是 d 的约数之一,我们将他及时的记录下来,等到全部的搜索结束,就能得到 d 的所有约数了