题目链接:Click here~~
题意:
问有多少个三元组 {x,y,z} ,使得 gcd(x,y,z) = G && lcm(x,y,z) = L。(顺序不同视为不同方案)
解题思路:
开始没注意括号里的条件,纠结了一天。
之前和队友 yzwsm 讨论过类似的二元组的问题,记得当时提到过将 G 和 L 分解质因子的方法,于是做这题时一下就联想到了。
首先一定有 G | L,在这个条件下,将两个数分解质因子,则一定能得到相同的质因子,且只是指数不同。(Note: 指数可以为 0 & 指数相同的项可以忽略)
即有 G = p1^a1 * p2^a2 * p3^a3 ……, L = p1^b1 * p2^b2 * p3^b3 ……(ai <= bi)。
由于方案的计数符合乘法原理,所以我们只需要考虑对于某个 pi 的方案数,最后相乘即可。
那么对于某个pi,第三个数的取值范围一定是 [a,b],我们分情况来考虑第三个数是否会等于a or b。
1、如果不等于,ans1 = A(3,2) * (b-a-1)。(Note:[a+1,b-1] => cnt = b-a-1)
2、如果等于,ans2 = C(3,1) * 2。
相加可化简为 ans = 6 * (b-a)。
还可以用容斥来考虑,转下。
另一种思考:容斥原理,对于p1,一共有(t1+1)^3种,但是没有最高位t1的选法是不合法的,减去,一共有t1^3种选法不合法,没有最低位0的选法是不合法的,也是t1^3,发现多减了,所以加上多减的既没有最高位也没有最低位的(t1-1)^3,通过化简得6*t1`````
#include <vector>
#include <stdio.h>
#include <string.h>
using namespace std;
vector< pair<int,int> > v1,v2;
void get_pp(int g,int l)
{
v1.clear();
v2.clear();
for(long long i=2;i*i<=l;i++)
{
int point_cnt1 = 0, point_cnt2 = 0;
while(g % i == 0)
{
g /= i;
point_cnt1 ++;
}
while(l % i == 0)
{
l /= i;
point_cnt2 ++;
}
if(point_cnt1 != point_cnt2)
{
v1.push_back(make_pair(i,point_cnt1));
v2.push_back(make_pair(i,point_cnt2));
}
}
if(l != 1 && g != l)
{
v1.push_back(make_pair(l,0));
v2.push_back(make_pair(l,1));
}
}
long long solve(int g,int l)
{
if(l % g != 0)
return 0;
get_pp(g,l);
long long ans = 1;
for(int i=0;i<(int)v1.size();i++)
ans *= 6 * (v2[i].second - v1[i].second);
return ans;
}
int main()
{
int T,gcd,lcm;
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&gcd,&lcm);
printf("%I64d\n",solve(gcd,lcm));
}
return 0;
}