lightoj 1215 Finding LCM
链接:http://www.lightoj.com/volume_showproblem.php?problem=1215
题意:已知 a, b, l 和 lcm(a, b, c) = l ,求最小的 c 的值。
思路:先找 l 的素因子并判断此因子是否为 a, b 的素因子,如果是,则判断他们各自的欧拉值的大小。因为 c 最大可能等于 l 的值,所以刚开始先把 l 的值赋给 c 。
当 l 中的某个素因子的欧拉值(lr1)大于 a,b 中相同的素因子的欧拉值(ar1, br1)时,c中肯定含有次素因子并且欧拉值(cr1 >= lr1 ),然而 c 是 l 的因子,所以(cr1 <= lr1 ), 所以 cr1 == lr1 ,不用进行处理。
当 l 中的某个素因子的欧拉值(lr1)等于(最大就是等于,不可能小于) a,b 中相同的素因子的欧拉值(ar1, br1)时,c中不一定含有次素因子,当 c 要取最小时,就可以不含有这个素因子,所以就把 c 中的 此素因子除干净。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 using namespace std; 5 6 typedef long long LL; 7 const int N = 1002; 8 bool tag[N]; 9 int prime[175]; 10 int k = 0; 11 LL a, b ,c, l; 12 13 LL stein(LL a, LL b) //stein 公式求最大公约数 14 { 15 if(a < b) swap(a, b); 16 if(!b) return a; 17 if(!(a&1) && !(b&1)) return 2* stein(a>>1, b>>1); 18 if(!(a&1)) return stein(a>>1, b); 19 if(!(b&1)) return stein(a, b>>1); 20 return stein((a-b)>>1, b); 21 } 22 //当然,你也可以用欧几里得 23 LL gcd(LL a, LL b) 24 { 25 return b ? gcd(b, a%b) : a; 26 } 27 28 int euler(LL *n, int m) //计算欧拉函数: 此函数中 n 值的变化会传回原处 29 { 30 int e = 0; 31 while(!((*n) % m)) 32 e++, (*n) /= m; 33 return e; 34 } 35 36 void prm() //素数表(线性素数筛法) 37 { 38 int i,j; 39 memset(tag, 0, sizeof(tag)); 40 tag[4] = 1, prime[k++] = 2; 41 for(i = 3; i < N; i += 2) 42 { 43 if(!tag[i]) prime[k++] = i; 44 for(j = 0; j < k && i*prime[j] < N; ++j) 45 { 46 tag[i*prime[j]] = 1; 47 if(i%prime[j] == 0) break; 48 } 49 } 50 } 51 52 void ct(int q) //计算c值 53 { 54 int i, cnta, cntb, cntL, cnt0, cs = 1; 55 c = l; // c 最大可能等于c, 先赋值为c,遇到情况在做除法减小它 56 if(l % (a/stein(a,b)*b)) //不可能的情况:l 不是(a, b)的最小公倍数的倍数 57 { 58 printf("Case %d: impossible ", q); 59 return; 60 } 61 for(i=0; i < k && (prime[i] <= a || prime[i] <= b); i++) // 62 { 63 cnta = cntb = 0; 64 if(!(l%prime[i])) //是某个素数倍数的时候 65 { 66 cntL = euler(&l, prime[i]); // l 部分欧拉函数值 67 if(!(a%prime[i])) // 当这个素数也是a 的因子的时候 68 cnta = euler(&a, prime[i]); // a 的部分欧拉函数值 69 if(!(b%prime[i])) //当这个素数也是b 的因子的时候 70 cntb = euler(&b,prime[i]); //同 a 的操作 71 cnt0 = cnta > cntb ? cnta : cntb; // 最小公倍数当然是取值较大欧拉值 72 /* 73 a,b里边因子的欧拉值肯定要小于等于l的相同的因子的欧拉值的,当相等时,c要取最小就必须不含此因子 74 当a, b 中的因子的欧拉值都小于l中的时,c中相同因子的欧拉值必须大于等于l中的值,最小当然取等于啦 75 这也是为什么下面的只处理等于的情况 76 */ 77 if(cntL == cnt0) 78 while(cnt0--) 79 c /= prime[i]; 80 } 81 } 82 if(a > 1 && euler(&l, a) <= 1) c /= a; //当 a 中含有大于1000的素数时的处理a 83 if(b > 1 && euler(&l, b) <= 1) c /= b; //当 b 中含有大于1000的素数时的处理b 84 printf("Case %d: %lld ", q, c); 85 } 86 87 int main() 88 { 89 int t, q=1; 90 prm(); 91 scanf("%d", &t); 92 while(t--) 93 { 94 scanf("%lld%lld%lld", &a, &b, &l); 95 ct(q++); 96 } 97 return 0; 98 }