lightoj 1215

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\n", 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\n", 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 }

 

 

 

 

 

转载于:https://www.cnblogs.com/Duahanlang/p/3233445.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值