LCM from 1 to n

LightOJ 1289 LCM from 1 to n

  • Description
    Given an integer n, you have to find lcm(1, 2, 3, …, n)
    lcm means least common multiple. For example lcm(2, 5, 4) = 20,
    lcm(3, 9) = 9, lcm(6, 8, 12) = 24.

    Input Input starts with an integer T (≤ 10000), denoting the number
    of test cases. Each case starts with a line containing an integer n
    (2 ≤ n ≤ 108).

    Output For each case, print the case number and lcm(1, 2, 3, …, n).
    As the result can be very big, print the result modulo 232.

  • Sample Input
    5
    10
    5
    200
    15
    20

  • Sample Output
    Case 1: 2520
    Case 2: 60
    Case 3: 2300527488
    Case 4: 360360
    Case 5: 232792560

  • 利用唯一分解定理可以得出一个有趣的递归式:

    LCM(n+1)=LCM(n) |(n+1)不是一个素数p的方次,即p的k次方(k为正整数)
    LCM(n)*p |反之
    http://blog.csdn.net/dsjgslkgs/article/details/47983833
    这里有证明

  • 可以根据这个结论推出:LCM(n)=p1^r1*p2^r2*…*pk^rk (p为小于等于n的素数)

    参考:http://blog.csdn.net/acdreamers/article/details/18364107

  • 解题巧妙的地方有两个:
    1.筛法求素数时用位图压缩节省空间,代替普通的bool
    2.用sum表示一串素数的乘积,类似前缀和,实现算
          LCM(n)=p1^r1*p2^r2*…*pk^rk
     的方法巧妙。
     
    具体有点想法:
     int m=(int)pow(n+0.9,1.0/t); 
     算出小于n的最大的方次数(就这样叫它了。。)p^k的p
     if(m<2) break;  
     p(即m)都小于2这个最小的素数了,就退出了
     int pos=lower_bound(prime,prime+cnt,m) - prime;
    if(prime[pos]!=m) pos–; 
    ans*=sum[pos];
    特别注意t++; t就是次数k。t在递增,因此可以用sum这个前缀和一样的东西,将所有p1^r1*p2^r2*…*pk^rk乘起来。

#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define N 100000000
#define MAXP 6000000
#define SHIFT 5
const int radix=(1<<SHIFT)-1;
int cnt,prime[MAXP+10];
unsigned int sum[MAXP+10];
int flag[(N>>SHIFT)+10];
void SetBit(int x)
{
    flag[x>>SHIFT] |= (1<<(x&radix));
}
bool CheckBit(int x)
{
    return flag[x>>SHIFT] & (1<<(x&radix));
}
void GetPrime()
{
    int side=sqrt(N+0.5);
    for(int i=2;i<=side;i++)
        if(!CheckBit(i)){
            prime[cnt++]=i;
            for(int j=i*i;j<=N;j+=i)
                SetBit(j);
        }
    for(int i=side+1;i<=N;i++)
        if(!CheckBit(i))
            prime[cnt++]=i;
}
void Init()
{
    sum[0]=prime[0];
    for(int i=1;i<cnt;i++)
        sum[i]=sum[i-1]*prime[i];
}
int main()
{
    GetPrime();
    Init();
    int T,n;
    scanf("%d",&T);
    for(int i=1;i<=T;i++){
        scanf("%d",&n);
        unsigned int ans=1;
        int t=1;
        while(true){
            int m=(int)pow(n+0.9,1.0/t);
            if(m<2) break;
            int pos=lower_bound(prime,prime+cnt,m) - prime;
            if(prime[pos]!=m) pos--;
            ans*=sum[pos];
            t++;
        }
        printf("Case %d: %u\n",i,ans);
    }
}
posted @ 2015-08-25 20:38  KatarinaYuan  阅读(353)  评论(0编辑  收藏  举报