牛客寒假集训J题一群小青蛙呱蹦呱蹦呱

123 阅读2分钟

题目链接

题目链接

求n个数的LCM。

由唯一分解定理得:
a = p 1 k 1 × p 2 k 2 × p 3 k 3 × . . . × p m k m a=p_1^{k_1}\times p_2^{k_2}\times p_3^{k_3}\times ...\times p_m^{k_m} a=p1k1​​×p2k2​​×p3k3​​×...×pmkm​​
b = p 1 j 1 × p 2 j 2 × p 3 j 3 × . . . × p m j m b=p_1^{j_1}\times p_2^{j_2}\times p_3^{j_3}\times ...\times p_m^{j_m} b=p1j1​​×p2j2​​×p3j3​​×...×pmjm​​
其中p为质数。

g c d ( a , b ) = p 1 m i n ( k 1 , j 1 ) × p 2 m i n ( k 2 , j 2 ) × p 3 m i n ( k 3 , j 3 ) × . . . × p m m i n ( k m , j m ) gcd(a,b)=p_1^{min(k_1,j_1)}\times p_2^{min(k_2,j_2)}\times p_3^{min(k_3,j_3)}\times ...\times p_m^{min(k_m,j_m)} gcd(a,b)=p1min(k1​,j1​)​×p2min(k2​,j2​)​×p3min(k3​,j3​)​×...×pmmin(km​,jm​)​

l c m ( a , b ) = p 1 m a x ( k 1 , j 1 ) × p 2 m a x ( k 2 , j 2 ) × p 3 m a x ( k 3 , j 3 ) × . . . × p m m a x ( k m , j m ) lcm(a,b)=p_1^{max(k_1,j_1)}\times p_2^{max(k_2,j_2)}\times p_3^{max(k_3,j_3)}\times ...\times p_m^{max(k_m,j_m)} lcm(a,b)=p1max(k1​,j1​)​×p2max(k2​,j2​)​×p3max(k3​,j3​)​×...×pmmax(km​,jm​)​

上面的性质可以由2个推广到n个。

题解

这题显然是要求所有n以内,包含两个及以上不同质因子的数的LCM。

根据上述性质,要求LCM,我们只需求出所有p的max值即可,显然,和2组合时,每个p可以取到max。

因此我们可以用欧拉筛筛出所有素数,然后对于每个素数,看能用2和最多几个该素数相乘得到。

2本身比较特殊,因为题目要求必须两个不同的质因子,所以计算2的贡献时,我们选用第二小的3即可。

还有一个小细节:

欧拉筛筛素数的时候,只需筛到n/2,因为(n/2,n]的素数肯定不可能和另一个素数(最小为2)相乘能得到n。

代码

/*
 * @Author: hesorchen
 * @Date: 2020-12-16 21:04:44
 * @LastEditTime: 2021-02-02 20:18:51
 * @Description: 栽种绝处的花
 */

#include <bits/stdc++.h>
using namespace std;

#define MAXN 160000000
// #define MAXN 80000000 //只需筛到n/2

int preme[16000010], cot;
bool ispreme[160000010];
void pre()
{
    ispreme[0] = ispreme[1] = 1;
    for (int i = 2; i <= MAXN; i++)
    {
        if (!ispreme[i])
            preme[++cot] = i;
        for (int j = 1; j <= cot && preme[j] * i <= MAXN; j++)
        {
            ispreme[preme[j] * i] = 1;
            if (i % preme[j] == 0)
                break;
        }
    }
}
long long ans = 1, mod = 1000000007;
int main()
{
    pre();
    int n;
    cin >> n;
    long long temp = n / 3; //先特判质数2,用3组合最省
    while (temp >= 2)
    {
        temp /= 2;
        ans = (ans * 2) % mod;
    }
    for (int i = 2; i <= cot; i++)
    {
        long long temp = n / 2, f = 0;
        while (temp >= preme[i])
        {
            f = 1;
            temp /= preme[i];
            ans = (ans * preme[i]) % mod;
        }
        if (!f)
            break;
    }
    if (ans >= 6)
        cout << ans << endl;
    else
        cout << "empty" << endl;
    return 0;
}

参考资料