LightOJ 1289 LCM from 1 to n(位图标记+素数筛
Posted wzgg
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LightOJ 1289 LCM from 1 to n(位图标记+素数筛相关的知识,希望对你有一定的参考价值。
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 ", 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 ", ++l, solve()); } return 0; }
以上是关于LightOJ 1289 LCM from 1 to n(位图标记+素数筛的主要内容,如果未能解决你的问题,请参考以下文章
LightOJ 1236 - Pairs Forming LCM(素因子分解)
LightOJ 1236 Pairs Forming LCM(算数基本定理)