LightOJ 1289 LCM from 1 to n

来源:互联网 发布:ppt图片 数据分析 编辑:程序博客网 时间:2024/06/10 00:10

题意:

lcm(1,2,....n)
数据范围:
n108, 104 组测试数据

思路:

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) = ….
所以我们可以看出,计算lcm的时候,不断乘过去的时候,只有当乘数为素数的 整数 次幂时,才会增大答案,所以做法就很简单了!
预处理(1108)素数的前缀积,二分找到这个答案,然后更新答案!
比如 x=10的话,ans=2357 (素数前缀积)
然后用素数 2,3 来更新答案(注意大于 x 的素数是不会更新答案的),所以 ans=ans231321

这样明显是不够的,MLE
首先是尝试去块处理前缀乘积,缩小内存,还是MLE
然后灵机一动,flag 数组这个改为 bitset 实现,因为bitset内部本质就是采用位图来搞的!终于AC!

代码:

#include <bits/stdc++.h>using namespace std;typedef unsigned int UI;const int N = 1e8 + 10;const int BASE = 100;int cnt, prime[5761460];bitset<N> flag;UI f[5761460/BASE];void init(){    int i, j;    cnt = 0;    for(int i = 2;i < N;i ++)    {        if(!flag[i]) prime[cnt ++] = i;        for(j = 0;j < cnt && i * prime[j] < N;j ++) {            flag[i * prime[j]] = 1;            if(i % prime[j] == 0) break;        }    }    UI tmp = 1u;    f[0] = 1u;    for(int i = 0;i < cnt;i ++) {        tmp = tmp * (UI)prime[i];        if((i+1) % BASE == 0) f[(i+1)/BASE] = tmp;    }}int main(){    int T, ca = 0;    scanf("%d", &T);    init();    while(T --)    {        int n;        scanf("%d", &n);        int p = lower_bound(prime, prime + cnt, n) - prime;        if(prime[p] > n) p --;        UI ans = f[(p + 1)/BASE];        for(int i = (p+1)/BASE * BASE;i <= p;i ++) ans = ans * (UI)prime[i];        for(int i = 0;1LL * prime[i] * prime[i] <= n;i ++)        {            int cnt = 0, tmp = n;            while(tmp >= prime[i]) cnt ++, tmp /= prime[i];            for(int j = 2;j <= cnt;j ++) ans = ans * (UI)prime[i];        }        printf("Case %d: %u\n", ++ca, ans);    }    return 0;}
0 0