题目链接:https://codeforces.com/contest/1154/problem/G
题意:给你n个数,你找出两个数,lcm最小。
解题心得:假设从n中选两个数x和y,那么
l
c
m
=
x
∗
y
/
g
c
d
lcm = x * y / gcd
lcm=x∗y/gcd,当gcd相同的时候肯定是最小的两个数x和y才可能产生最小的lcm,这样就可以枚举所有的gcd,然后找到两个最小的数他们都有因子gcd,这样就可以使用一个类似埃筛法的写法,复杂度为:
(
n
+
n
/
2
+
n
/
3
+
n
/
4
+
n
/
5....
+
n
/
n
)
≈
(
n
×
l
o
g
n
)
(n+n/2 + n/3 + n/4 + n/5 ....+ n/n) \approx (n×logn)
(n+n/2+n/3+n/4+n/5....+n/n)≈(n×logn)
这里有个大佬的复杂度证明:https://www.cnblogs.com/qscqesze/p/4317860.html
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e7+10;
typedef long long ll;
int num[maxn], cnt[maxn], n;//cnt[i]记录数值为i的数出现的次数
vector <int> ve[maxn], pos[maxn];//ve[i]记录以i为因子的最小的两个数, pos[i]记录数值为i的数的位置
void init() {
scanf("%d", &n);
for(int i=1;i<=n;i++) {
scanf("%d", &num[i]);
cnt[num[i]]++;
pos[num[i]].push_back(i);
}
}
void deal() {
//处理出ve的值
for(int i=1;i<maxn;i++) {
for(int j=i;j<maxn;j+=i) {
if(cnt[j] == 1) {
ve[i].push_back(j);
} else if(cnt[j] >= 2) {
ve[i].push_back(j);
if(ve[i].size() < 2) ve[i].push_back(j);
}
if(ve[i].size() == 2) break;
}
}
}
int main() {
// freopen("1.in", "r", stdin);
init();
deal();
//找到最小的lcm
ll Min = LLONG_MAX;
ll x, y;
for(int i=1;i<maxn;i++) {
if(ve[i].size() != 2) continue;
ll a = ve[i][0];
ll b = ve[i][1];
ll temp = a * b / __gcd(a, b);
if(temp < Min) {
Min = temp;
if(a != b) {
x = pos[a][0];
y = pos[b][0];
} else {
x = pos[a][0];
y = pos[a][1];
}
}
}
if(x > y) swap(x, y);
printf("%lld %lld\n", x, y);
// cout<<Min<<endl;
}