【数论】【算术基本定理】[LightOJ1289]LCM from 1 to n

题目
分析:设L(n)为LCM(1,2,3……n),则有

这里写图片描述

若n+1不是 质数的完全平方,则可将质因数分解成p1^a1*p2^a2*……pn^an,对于每个pi^ai,显然<n,且两两互质,所以p1^a1*p2^a2*……pn^an|L(n),所以n+1|L(n),L(n +1)=L(n)

若n+1是质数的完全平方,则n+1=p^k,p^k不整除1….n,p^k不整除L(n),因为p^(k-1)|L(n),所以p^(k-1)*p|L(n)*p,所以L(n+1)=L(n)*p。

筛法求素数时用位图压缩节省空间。

在实现过程中,如果暴力检查一个数是不是素数的幂,显然十分慢,所以计算所有素数的前缀和,对于前缀和的用法,看注释

#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
#define MAXP 6000000
#define MAXN 100000000
#define SHIFT 5
int p[MAXP+10],pcnt,n,T;
unsigned int sum[MAXP+10];
int f[(MAXN+10)>>SHIFT];
void SetBit(int x){
    f[x>>SHIFT]|=1<<(x&((1<<SHIFT)-1));
}
bool GetBit(int x){
    return f[x>>SHIFT]&(1<<(x&((1<<SHIFT)-1)));
}
void isprime(){
    int i,j,t=sqrt(MAXN+0.5);
    for(i=2;i<=t;i++){
        if(!GetBit(i)){
            p[++pcnt]=i;
            for(j=i*i;j<=MAXN;j+=i)
                SetBit(j);
        }
    }
    for(;i<=MAXN;i++)
        if(!GetBit(i))
            p[++pcnt]=i;
}
void prepare(){
    sum[0]=1;
    for(int i=1;i<=pcnt;i++)
        sum[i]=sum[i-1]*p[i];
}
int main()
{
    isprime();
    prepare();
    scanf("%d",&T);
    int Case=0;
    while(T--){
        scanf("%d",&n);
        printf("Case %d: ",++Case);
        unsigned int ans=1;
        int cnt=1;
        while(1)
        {
            int m=(int)pow(n+0.9,1.0/cnt);     //求n的cnt次方根
            if(m<2)
                break;
            int i=lower_bound(p+1,p+pcnt+1,m)-p;       //对于前i个素数,它们的cnt次方<=n
            if(p[i]!=m)
                i--;
            ans*=sum[i];                        //相当于枚举了前i个数的cnt次方
            cnt++;
        }
    printf("%u\n",ans);
    }
}

你可能感兴趣的:(C++,数论,noip,lightoj)