中石油 问题 B: 赛博朋克(数学)

题目链接

题意:

n个数,先两两求最小公倍数,然后再对公倍数求最大公因数.

思路:

将题意整合一下就是 把这些数分解质因子,然后针对每个质因子,第二小的就是这个质数的代价.
怎么得来的那?
因为我们先求最小公倍数,在求最大公因数,那么我们找到两个针对某一质数,代价最小的两个数,这个地方有点难理解,
假设这些数中有 8,9,40,66,80,34,70, 然后我们针对质数2来找到代价最小的两个数
原数8 9 40 66 80 34 70
针对质数2的代价8 0 8 2 16 2 2所以我们看出最小的两个代价是0和2所以求出的最小公倍数就有代价2,然后在求最大公因数,因为我们找出的是最小的两个代价,所以其他的最小公倍数的代价,都大于或等于2,所以最后求最大公因数就是2
这是光针对质数2了来讲的,针对其他的质数也一样

知道这之后就是维护时间复杂度了,因为2e5中的质数将近有2e4个n又是1e5所以枚举所有质数很显然不现实.
所以我们可以先筛出\(\sqrt{2e5}\)之内的素数,剩下的,我们分解质因数时,剩的肯定就是一个素数,那么我们将其加入到素数列表中即可.

还有就是维护第二小的质数代价,我们就得看看0代价的数量,如果0代价的数量大于等于2,那么这个质数就不会产生代价.

ll t;
ll n, k, cnt;
ll a[maxn];
 
bool isprime[maxn];
ll prime[maxn], dis[maxn], vis[maxn];
void p()
{
    for(int i = 2; i <= sqrt(2e5 + 10); i++)
    {
        if(!isprime[i]) prime[++cnt] = i;
        for(int j = 1; j <= cnt && i * prime[j] <= sqrt(2e5 + 10) ; j++)
        {
            isprime[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;
        }
    }
}
 
void solve()
{
    p();
    scanf("%lld", &n);
    ll maxx = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%lld", &a[i]);
        maxx = max(maxx, a[i]);
        for(int j = 1; j <= cnt; j++)
        {
            ll num = 1;
            while(a[i] % prime[j] == 0)
            {
                a[i] /= prime[j];
                num = num * prime[j];
            }
 
            if(num != 1) dis[num]++, vis[prime[j]]++;
 
            if(a[i] == 1) break;
        }
        if(a[i] > 1) prime[++cnt] = a[i], dis[a[i]]++, vis[a[i]]++;
    }
    ll ans = 1;
    for(int i = 1; i <= cnt; i++)
    {
        if(n - vis[prime[i]] >= 2)  continue;
        ll num = 2 - (n - vis[prime[i]]);
        for(int j = prime[i]; j < maxx; j *= prime[i])
        {
            num -= dis[j];
            if(num <= 0)
            {
                ans = ans * j;
                break;
            }
        }
    }
 
    printf("%lld\n",ans);
}
posted @ 2021-07-22 10:44  `KingZhang`  阅读(63)  评论(1编辑  收藏  举报