首页 > 代码库 > LIGHT OJ 1289 LCM from 1 to n

LIGHT OJ 1289 LCM from 1 to n

题目链接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=26999

题意:

给定一个n,求,LCM(1,2,3,.....,n)
分析:

几个数的最小公倍数等于这些数的素因子的最高次幂的乘积;

由于求1到n的所有的数的最小公倍数 ,所有的素因子为小于等于n的所有素数

因此我们至于要求出这些素数在n内的最高次幂即可。

我们可以先预处理出所有的素数的乘积,然后再乘上到n的p[i]最高次幂/p[i]。

因为是对2^32取模 我们可以用unsigned int来存。

还有一个困难时筛求素数的时候我们开不出那么大的数组 ,因此我们需要用到一个新的工具

位图,就不在这里讲解了。

位图的讲解:http://dongxicheng.org/structure/bitmap/

用位图筛素数的方法:http://blog.csdn.net/raomeng1/article/details/8520199

代码如下:

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn =100000009;
typedef unsigned int UUI;
int vis[maxn/32+50];
UUI mul[5800000];
int p[5800000],cnt,n;


void init()//运用位图来筛素数+预处理素数的积
{
    cnt=1;
    p[0]=mul[0]=2;
    for(int i=3;i<maxn;i+=2){
        if(!(vis[i/32]&(1<<((i/2)%16)))){
            p[cnt]=i;
            mul[cnt]=mul[cnt-1]*i;
            cnt++;
            for(int j=i*3;j<maxn;j+=2*i)
                vis[j/32]|=(1<<((j/2)%16));
        }
    }
}

UUI solve()
{
    int pos=upper_bound(p,p+cnt,n)-p-1;//定位到第一个小于n的素数
    UUI ans = mul[pos];
    for(int i=0;i<cnt&&p[i]*p[i]<=n;i++){
        int tmp=p[i];
        int tt=p[i]*p[i];
        while(tt/tmp==p[i]&&tt<=n){//得到max(p[i]^k)<=n;用tmp*p[i]会爆int;
            tmp*=p[i];
            tt*=p[i];
        }
        ans*=(tmp/p[i]);
    }
    return ans;
}
int main()
{
    int t,cas=1;
    scanf("%d",&t);
    init();
    while(t--){
        scanf("%d",&n);
        printf ("Case %d: %u\n",cas++,solve());
    }
    return 0;
}


LIGHT OJ 1289 LCM from 1 to n