GCD and LCM
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 3104 Accepted Submission(s): 1357
Problem Description
Given two positive integers G and L, could you tell me how many solutions of (x, y, z) there are, satisfying that gcd(x, y, z) = G and lcm(x, y, z) = L?
Note, gcd(x, y, z) means the greatest common divisor of x, y and z, while lcm(x, y, z) means the least common multiple of x, y and z.
Note 2, (1, 2, 3) and (1, 3, 2) are two different solutions.
Input
First line comes an integer T (T <= 12), telling the number of test cases.
The next T lines, each contains two positive 32-bit signed integers, G and L.
It’s guaranteed that each answer will fit in a 32-bit signed integer.
Output
For each test case, print one line with the number of solutions satisfying the conditions above.
Sample Input
2 6 72 7 33
Sample Output
72 0
Source
题意:
问题描述
给定两个正整数G和L,你能告诉我(x, y, z)有多少个解,满足gcd(x, y, z) = G和lcm(x, y, z) = L?
注意,gcd(x, y, z)表示x、y和z的最大公约数,lcm(x, y, z)表示x、y和z的最小公约数。
注2,(1,2,3)和(1,3,2)是两个不同的解。
输入
第一行是一个整数T (T <= 12),告诉测试用例的数量。
下一行T,每一行都包含两个正的32位有符号整数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 <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define N 100000
#define ll long long
using namespace std;
ll d[N][2],e[N][2],cntn,cntm;
void devide(int n,int m){
cntn=cntm=0;
for (int i=2; i*i<=n; i++) {
if (n%i==0) {
int num=0;
while (n%i==0) {
num++;
n=n/i;
}
++cntn;
d[cntn][0]=i;d[cntn][1]=num;
}
}
for (int i=2; i*i<=m; i++) {
if (m%i==0) {
int num=0;
while (m%i==0) {
num=num+1;
m=m/i;
}
++cntm;
e[cntm][0]=i,e[cntm][1]=num;
}
}
if (n>1) d[++cntn][0]=n,d[cntn][1]=1;
if (m>1) e[++cntm][0]=m,e[cntm][1]=1;
}
ll solve(int n,int m){
if (m%n!=0) return 0;
devide(n,m );
ll ans=1,v=0;
for (int i=1; i<=cntm; i++) {
int flag=0;
for (int j=1; j<=cntn; j++) {
if (e[i][0]==d[j][0]) {
flag=1;
v=j;
break;
}
}
if (!flag) {
ans=ans*6*e[i][1];
}else{
ll t=e[i][1]-d[v][1];
if (t==0) continue;
ans=ans*6*t;
}
}
return ans;
}
int main(){
int T;
int n,m;
cin>>T;
while (T--) {
cin>>n>>m;
ll ans=solve(n, m);
cout<<ans<<endl;
}
return 0;
}