1. 程式人生 > 實用技巧 >LCM from 1 to n LightOJ - 1289(點陣圖篩法,數論好題)

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