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;
}