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