LCM from 1 to n LightOJ - 1289

题目:LCM from 1 to n LightOJ - 1289 

题意:给你一个数n求LCM(1, 2,........,n ),LCM 为最大公约数。

思路:该题可以根据n = 10找一下规律。

1    2   3    4    5    6     7     8     9    10

最大公约数为5 * 7 * 8* 9 = 2520,可以看出规律LCM等于p1^x1*p2^x2*p3^x3........pn^xn, p1...pn,为连续的质数。那么xi怎么求,n不断的除以pi,例如上面的例子,8就是10不断的除以2,一共除以3次2,所以2^3 = 8,所以8出来了,9同样的道理,10不断的除以3z最多除以两次3,3^2 = 9,那么9就出来了。所以需要把素数筛出来,但是数据的范围是1e8所以直接开数组不可以,所以需要位图,只需要理解位图的原理,咱么有比较好用的STL的容器bitset和位图的原理一样,可以压缩空间。那么我们直接上欧拉筛,把素数直接筛出来。虽然把素数筛出来但是还是存在问题的,如果你把所有的素数直接遍历到n之间最大的素数,最终的结果指定超时,所以我们就想到,前缀积(就是前缀和的思想),然后查找到比n小的最大的素数,然后在重新遍历以下pri[i]*pri[i] <= n(大于这个条件的素数就只有一个,已经利用前缀积求出来了)的数,求出n连续除以pri[i]的个数减去1,为什么减去1,因为前缀积已经求了,所以需要减去1.

代码:

#include<bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 1e8+5;
unsigned int pri[5800000];
const long long mod = 1LL<<32;
unsigned int sum[5800000];
bitset<maxn>vis;//位图压缩空间
int cn = 1;
void Prime(){//欧拉筛
     pri[0] = 0;
     for(int i = 2; i < maxn; i++){
        if(!vis[i])pri[cn++] = i;
        for(int j = 1; j < cn && i * pri[j] < maxn; j++){
            vis[i*pri[j]] = true;
            if(i % pri[j] == 0)break;
        }
     }
     sum[0] = 1;
     for(int i = 1; i < cn; i++){//前缀积
        sum[i] = sum[i-1]*pri[i];
     }
    // pri[cn] = maxn;
}
LL q_pow(int a, int b){//快速幂
   LL ans = 1, base = a;
   while(b){
       if(b & 1)ans = (ans * base) % mod;
       base = (base * base) % mod;
       b >>= 1;
   }
return ans;
}
int main(){
    Prime();
    int T;
    scanf("%d", &T);
    int ca = 0;
    //cout<<cn<<endl;
    while(T--){
        int n;
        scanf("%d", &n);
        int pos = upper_bound(pri+1, pri+cn, n) - pri-1;//二分查找第一个比n大的数,然后减去1,就小于等于n
        LL ans = sum[pos] % mod;
        for(int i = 1; i < cn && pri[i]*pri[i] <= n; i++){//
            int t = n;
            int k = 0;
            while(t / pri[i]){
                t /= pri[i];
                k++;
            }
            ans = q_pow(pri[i], --k)*ans % mod;
        }
        printf("Case %d: %lld\n",++ca, ans%mod);
    }

return 0;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值