1154G Minimum Possible LCM 【埃氏筛法枚举公约数】

传送门
 

题意:n个数中最小公倍数数值最小的两个数的下标。

参考博客:https://blog.csdn.net/qq_41157137/article/details/89353527

思路:

                                               lcm(x,y)=\frac{x*y}{gcd(x,y)}

对于包含 d=gcd(x,y)的数  x_{1},x_{2},x_{3},x_{4},x_{5}\cdot \cdot \cdot x_{i} (x_{1}< x_{2}< x_{3}< x_{4}< x_{5}< x_{i} )

如果 d是 x_{1},x_{2}x_{1},x_{2}的最大公约数的最大公约数,那么lcm(x,y)一定小于\frac{x_{1}*x_{3}}{d},后面就可以不用考虑了

如果d不是x_{1},x_{2}的最大公约数不是d的最共公约数( 满足dgcd(x_{1},x_{2})的因子,比如d=2,x_{1}=4,x_{2}=8 )。那么 lcm(x_{1},x_{2}) 也一定小于

\frac{x_{1}*x_{2}}{d},如果dx_{1},x_{2}的最大公约数,同样lcm(x_{1},x_{2})<\frac{x_{1}*x_{3}}{d},后面就可以不用考虑了

所以我们只需要得到每个d的倍数的前2项即可,时间复杂度(1e7*log(le7))

代码:

///#include <bits/stdc++.h>
///#include <unordered_map>
///#include <unordered_set>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <string>
#include <cmath>
#include <queue>
#include <set>
#include <stack>
#include <map>
#include <new>
#include <ctime>
#include <vector>

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const double pai = acos(-1.0);
const double E = exp(1.0);
const int INF = 0x3f3f3f3f;
const long long mod = 1e9 + 7;

int n, maxn, p1, p2, lcm[10000005], num[10000005];
ll ans_lcm = 1e18 + 7;
bool vis[10000005];

int main() {
    maxn = 0;
    memset(vis, false, sizeof(vis));
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &num[i]);
        maxn = max(maxn, num[i]);
        ///存在相同数字的情况
        if (vis[num[i]]) {
            if (ans_lcm > num[i]) {
                ans_lcm = num[i];
                p1 = i;
                p2 = lcm[num[i]];
            }
        } else
            vis[num[i]] = 1, lcm[num[i]] = i;
    }
    for (int i = 1; i <= maxn; i++) {///枚举公因子
        int pre = -1;
        for (int j = i; j <= maxn; j+=i) {///枚举数字
            if (vis[j] && pre == -1) {
                pre = j;
            } else if (vis[j] && pre != -1) {
                ll now_lcm = (ll) pre / __gcd(pre, j) * j;
                if (ans_lcm > now_lcm) {
                    ans_lcm = now_lcm;
                    p1 = lcm[pre];
                    p2 = lcm[j];
                }
                break;
            }
        }
    }
    printf("%d %d\n", min(p1, p2), max(p1, p2));
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值