LightOJ 1289 LCM from 1 to n


LCM  FROM  1 TO  N


题意:  求1 到 n  的LCM(最小公倍数)


素数的另外一种筛法:  (大概就是欧拉筛的优化)


思路: 首先求1 ~n  的LCM ,只需要求出 n 以内的所有素数的最高次幂。

 10:        2^3*3^2*5*7

  5:         2^2*3*5

又由于 直接筛出  1e8  的素数会爆内存。

所以要用一个叫 位图 的来优化存储。


位图模板:

#define INT_BITS sizeof(int)

#define SHIFT 5 // 2^5=32

#define MASK 0x1f // 2^5=32

#define MAX 1024*1024*1024 //max number

int bitmap[MAX / INT_BITS];

/*
* 设置第i位
 
* i >> SHIFT 相当于 i / (2 ^ SHIFT),
 
* i&MASK相当于mod操作 m mod n 运算
 
*/
void set(int i)
{
    bitmap[i >> SHIFT] |= 1 << (i & MASK);
}

//获取第i位 
int test(int i)
{
    return bitmap[i >> SHIFT] & (1 << (i & MASK));
}
//清除第i位
int clear(int i)
{
    return bitmap[i >> SHIFT] & ~(1 << (i & MASK));
}




代码:


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


const int N =100000007;
int vis[N/32+50];
typedef long long ll ;
ll MOD=1ll<<32;
int pri[6000000],len=0;
unsigned int sum[6000000];


bool Get(int i)
{
    int x=i/32,y=i%32;
    return 1<<y & vis[x];

}
void Set(int i)
{
    int x=i/32,y=i%32;
    vis[x]|=1<<y;

}
void init()
{
    len=0;
    for(int i=2;i<=N;i++)
    {
        if(!Get(i))
            pri[len++]=i;
        for(int j=0;j<len&&i*pri[j]<=N;j++)
        {
            Set(i*pri[j]);
            if(i%pri[j]==0) break;
        }
    }
    sum[0]=pri[0];
    for(int i = 1;i < len; i++)    sum[i] = (ll)sum[i-1]*pri[i]%MOD;
}
unsigned int  solve(int n)
{
    int p=upper_bound(pri,pri+len, n)-pri-1;   //找到最接近n 的素数
    unsigned int ans=sum[p];
    for(int i=0;i<len&&pri[i]*pri[i]<=n;i++)
    {
        int mx=pri[i];
        int tm=pri[i]*pri[i];
        while(tm/mx==pri[i]&&tm<=n) //防止 爆 int;
        {
            tm*=pri[i];
            mx*=pri[i];
        }
        ans*=(mx/pri[i]);
    }
    return ans;
}
int main()
{
    int T;
    scanf("%d",&T);
    int kase=1;
    init();
    while(T--)
    {
        int n;
        scanf("%d",&n);
        printf("Case %d: %u\n",kase++,solve(n));

    }
    return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值