您的位置:首页 > 其它

Light 1289 - LCM from 1 to n (位图标记+素数筛选)

2015-07-16 21:35 453 查看
题目链接:

  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位二进制,我们就可以把每一位当做一个数,又因为偶数除了二以外都不是素数,所以我们只需要筛选奇数。

#include <bits/stdc++.h>
using namespace std;
typedef unsigned int UI;
const int maxn = 100000005;
const int N = 5800000;
UI mul
;
int vis[maxn/32+10], p
;
int cnt, n;
void init ()
{
cnt = 1;
p[0] = mul[0] = 2;
for (int i=3; i<maxn; i+=2)
if (!(vis[i/32]&(1<<((i/2)%16))))
{//寻找代表i的哪一位,偶数不占位数
p[cnt] = i;
mul[cnt] = mul[cnt-1] * i;
for (int j=3*i; j<maxn; j+=2*i)
vis[j/32] |= (1<<((j/2)%16));//删除有因子的位数
cnt ++;
}
//printf ("%d\n", cnt);
}
UI solve ()
{
int pos = upper_bound(p, p+cnt, n) - p - 1;//找出最大的比n小的素数
UI ans = mul[pos];
for (int i=0; i<cnt&&p[i]*p[i]<=n; i++)
{
int tem = p[i];
int tt = p[i] * p[i];//这个tt很有可能溢出int(害的本宝宝wa了好几次)
while (tt/tem == p[i] && tt<=n)
{
tem *= p[i];
tt *= p[i];
}
ans *= tem / p[i];
}
return ans;
}
int main ()
{
int t, l = 0;
init ();
scanf ("%d", &t);
while (t --)
{
scanf ("%d", &n);
printf ("Case %d: %u\n", ++l, solve());
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: