hdu_4497GCD and LCM(合数分解)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4497
GCD and LCM
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65535/65535 K (Java/Others)
Total Submission(s): 2151 Accepted Submission(s): 955
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.
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.
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
题意:给出三个数的最大公约数和最小公倍数,让求abc这三个数可能的情况,注意ABC的位置不同算不同的情况
考虑先分解最小公倍数。合数分解后,再分解最大公约数,可知,如果最大公约数中有最小公倍数中没有的质因数因子的话,那么答案肯定为0
然后考虑每一个因子pi有设合数分解最小公倍数的个数为bi合数分解最大公约数的个数为bi
下面有两种考虑方法
排列组合:易得三个数中的对于pi的情况必须有一个个数是bi,另一个是ai,然后就可以先选出两个位置一个bi一个ai然后最后一个位置上的个数一定介于ai和bi之间即(bi-ai-1)种情况。
所以最后的公式为ans *= A(3,2)*(bi-ai-1) = 6*(bi-ai-1) ;
注意,如果先筛素数的时候筛到1^6 然后如果L除以最后一个素数的时候不等于1,那么说明它(L的最后一个因子)一定是大于10^6的一个素数,因为10^12 = 10^6^2 > x^2>y;如果y存在一个非素数的因子k的话,有k*t = y 且k>x,则t<x则t已经被筛掉了。所以剩下的因子一定是素因子。一开始没有考虑这种特殊情况wa掉了。。。
注意,还要注意只有当(bi-ai-1) 有意义的时候才可以计算,因为如果bi==ai的时候可以发现正确结果是对于这一位应该是只用一种情况,就是三个数都相等,所以要特判一下。。。。后来又因为这个wa了一次~~~~(>_<)~~~~
容斥定理:同样是考虑每个因子,有所有的情况是每个位置都可以取(bi-ai+1)种情况即(bi-ai+1)^3,要减去没有bi个因子的情况和没有ai个因子的情况即2*(bi-ai)^3
然后发现减多了,要加上同时没有因子ai和bi的情况即(bi-ai-1)^3
这里同样要注意上面的注意。
1 //合数分解 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 #define ll long long 7 const int maxn = 1000005; 8 int prime[maxn]; 9 bool pri[maxn]; 10 int cnt; 11 void init() 12 { 13 cnt = 0; 14 pri[0] = pri[1] = 1; 15 //prime[0] = 2; 16 for(int i = 2; i < maxn; i++){ 17 if(!pri[i]){ 18 19 prime[cnt++] = i; 20 for(int j = i+i; j < maxn; j+=i) 21 { 22 pri[j]=1; 23 } 24 } 25 } 26 return; 27 } 28 ll m1[10005],m2[10005]; 29 ll c1[10005],c2[10005]; 30 int main() 31 { 32 init(); 33 int T; 34 ll G,L; 35 scanf("%d",&T); 36 while(T--) 37 { 38 memset(m1,0,sizeof(m1)); 39 memset(c1,0,sizeof(c1)); 40 memset(m2,0,sizeof(m2)); 41 memset(c2,0,sizeof(c2)); 42 scanf("%lld%lld",&G,&L); 43 int tm = 0; 44 bool in = 0; 45 bool fl = 1; 46 //printf("%d\n",prime[1]); 47 if(L%G) fl = 0; 48 for(int i = 0; i< cnt; i++){ 49 while(prime[i]<=L&&L%prime[i]==0){ 50 L = L/prime[i]; 51 m2[tm] = prime[i]; 52 c2[tm]++; 53 in = 1; 54 } 55 if(in) tm++; 56 in = 0; 57 } 58 if(L!=1){ 59 m2[tm] = L; 60 c2[tm] = 1; 61 tm++; 62 } 63 for(int i = 0; i < tm; i++){ 64 while(m2[i]<=G&&G%m2[i]==0){ 65 G = G/m2[i]; 66 m1[i] = m2[i]; 67 c1[i]++; 68 } 69 in = 0; 70 } 71 if(G!=1){ 72 fl = 0; 73 } 74 /*puts("haha"); 75 for(int i = 0; i < tm; i++){ 76 printf("m1[%d]=%d; m2[%d]=%d;\n",i,m1[i],i,m2[i]); 77 printf("c1[%d]=%d; c2[%d]=%d;\n",i,c1[i],i,c2[i]); 78 } 79 */ 80 if(fl==0) {puts("0"); continue;} 81 ll ans = 1; 82 for(int i = 0; i < tm; i++){ 83 //需要特判当c1[i] =c2[i]的情况 84 ll E; 85 if(c1[i]==c2[i]) E = 0; 86 else E = c2[i]-c1[i]-1; 87 /* 88 也可以用排列组合的想法,每次找到两个数包含首尾的两个值,然后中间的一个在从所有可能中选取一个。 89 这样最后的公式就是A(3,2)*(c2[i]-c1[i]-1); 90 所以 91 if(c2[i]>c1[i]) ans = ans*6*(c2[i]-c1[i]-1); 92 */ 93 ans = ans*((c2[i]-c1[i]+1)*(c2[i]-c1[i]+1)*(c2[i]-c1[i]+1)-2*(c2[i]-c1[i])*(c2[i]-c1[i])*(c2[i]-c1[i])+E*E*E); 94 } 95 printf("%lld\n",ans); 96 } 97 return 0; 98 }