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
20Sample 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的素数)
解题巧妙的地方有两个:
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);
}
}