当前位置 : 主页 > 手机开发 > ROM >

LightOJ 1289 LCM from 1 to n(位图标记+素数筛

来源:互联网 收集:自由互联 发布时间:2021-06-10
https://vjudge.net/contest/324284#problem/B 数学水题,其实就是想写下位图。。和状压很像 题意:给n让求lcm(1,2,3,...,n),n=1e8 思路:显然ans = 所有小于n的素数p[i]的max(p[i]^k)相乘。由于空间太大,

https://vjudge.net/contest/324284#problem/B

数学水题,其实就是想写下位图。。和状压很像

题意:给n让求lcm(1,2,3,...,n),n<=1e8

思路:显然ans = 所有小于n的素数p[i]的max(p[i]^k)相乘。由于空间太大,装素数的数组开不下,要用位图,int可以保存32位二进制,我们可以把每一位当作一个数,又因为偶数除了2以外都不是素数,所以只需筛选奇数。

L(1) = 1

L(x+1) = { L(x) * p    if x+1 is a perfect power of prime p
         { L(x)        otherwise

L(2) = 1 * 2
L(3) = 1 * 2 * 3
L(4) = 1 * 2 * 3 * 2      // because 4 = 2^2
L(5) = 1 * 2 * 3 * 2 * 5
L(6) = 1 * 2 * 3 * 2 * 5  // 6 is not a perfect power of a prime
L(7) = 1 * 2 * 3 * 2 * 5 * 7




#include <bits/stdc++.h>
using namespace std;
typedef unsigned int UI;
const int maxn = 100000005;
const int N = 5800000;
UI mul[N];
int vis[maxn/32+10], p[N];
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
        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;
}
网友评论