题目链接:
http://www.lightoj.com/volume_showproblem.php?problem=1289
题目描述:
给出一个n,求出lcm(1,2,3......n)为多少?
解题思路:
lcm(1,2,3,......,n-1,n)等于所有小于n的素数p[i]的max(p[i]^k)相乘。
暴力求解的话,由于时间的限制,很自然的想打了素数线性打标法,但是空间限制无法申请辣么大的标记数组。
这个重要的时刻位图标记就闪亮登场啦!!!!
int可以保存32位二进制,我们就可以把每一位当做一个数,又因为偶数除了二以外都不是素数,所以我们只需要筛选奇数。
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef unsigned int UI; 4 const int maxn = 100000005; 5 const int N = 5800000; 6 UI mul[N]; 7 int vis[maxn/32+10], p[N]; 8 int cnt, n; 9 void init () 10 { 11 cnt = 1; 12 p[0] = mul[0] = 2; 13 for (int i=3; i<maxn; i+=2) 14 if (!(vis[i/32]&(1<<((i/2)%16)))) 15 {//寻找代表i的哪一位,偶数不占位数 16 p[cnt] = i; 17 mul[cnt] = mul[cnt-1] * i; 18 for (int j=3*i; j<maxn; j+=2*i) 19 vis[j/32] |= (1<<((j/2)%16));//删除有因子的位数 20 cnt ++; 21 } 22 //printf ("%d ", cnt); 23 } 24 UI solve () 25 { 26 int pos = upper_bound(p, p+cnt, n) - p - 1;//找出最大的比n小的素数 27 UI ans = mul[pos]; 28 for (int i=0; i<cnt&&p[i]*p[i]<=n; i++) 29 { 30 int tem = p[i]; 31 int tt = p[i] * p[i];//这个tt很有可能溢出int(害的本宝宝wa了好几次) 32 while (tt/tem == p[i] && tt<=n) 33 { 34 tem *= p[i]; 35 tt *= p[i]; 36 } 37 ans *= tem / p[i]; 38 } 39 return ans; 40 } 41 int main () 42 { 43 int t, l = 0; 44 init (); 45 scanf ("%d", &t); 46 while (t --) 47 { 48 scanf ("%d", &n); 49 printf ("Case %d: %u ", ++l, solve()); 50 } 51 return 0; 52 }