LCM from 1 to n LightOJ - 1289(位图筛法,数论好题)

题目链接

题意:求lcm(1,2,3,...,n),n<=1e8;

思路:很容易想到其答案为n之前的所有质因子的最大次幂的乘积。例如n=20,答案就是19*17*13*11*7*5*3^2*2^4。又容易发现可以通过根号n求出前面的最高次幂-1。然后打表前面的素数乘积即可求出答案。

但这题的时间和内存卡的非常好,内存需要用到位图,时间需要欧拉筛且而且在solve函数中的sqrt(n)操作也要注意,一不小心就时间超限。

#include <bits/stdc++.h>
using namespace std;
#define LL long long
typedef unsigned int uint;
const int N = 100000000;
const int maxn=1e8+5;
int k;
uint vis[maxn/32+50];
uint prime[6000000],a[6000000];//质数,质数乘积前缀 
void Set(int i)
{
    int x=i/32,y=i%32;
    vis[x]|=((uint)1)<<y;
}
int Get(int i)
{
    int x=i/32,y=i%32;
    return vis[x]&((uint)1<<y);
}
int cnt=0;
void PHI(int n)
{

//    t1=clock();
    for(int i=2; i<=n; i++)
    {
        if(Get(i)==0)prime[cnt++]=i;
        for(int j=0; j<cnt&&(LL)i*prime[j]<=n; j++)
        {
            Set(i*prime[j]);
            if(i%prime[j]==0)break;
        }
    }
//    t2=clock();
    prime[cnt++]=maxn; 
    a[0]=prime[0];
    for(int i=1; i<cnt; i++)a[i]=a[i-1]*prime[i];
}

void solve(int n)
{
    unsigned int ans=1;
    int w=upper_bound(prime,prime+cnt,n)-prime;
    //printf("w:%d\n",w);
    w--;
    for(int i=0; i<cnt&&(LL)prime[i]*prime[i]<=n; i++)
    {
        LL tp=prime[i];
        while(tp*prime[i]<=n)tp*=prime[i];
        ans*=tp/prime[i];
    }
//    printf("%u\n",ans);
    
    ans*=a[w];
    printf("%u\n",ans);
}
int main() {
    int t;
    int u=0;
    
    PHI(maxn-5);
    scanf("%d",&t);
    while(t--){
        int n;
        scanf("%d",&n);
        printf("Case %d: ",++u);
        solve(n);
    }
}

 

posted @ 2020-09-22 11:03  Ldler  Views(150)  Comments(0Edit  收藏  举报