题目
给你n(2<=n<=1e6)个数,1<=ai<=1e7
要求输出两个下标i和j,使得lcm(ai,aj)最小,
多解时,输出任意两个即可,但要保证i<j
思路来源
dreamoon巨神的CF代码
题解
首先,将每个出现的位置记在pos[]数组里,
考虑到,存在lcm(x,x)==x的情形,在读入的时候特判一下
再考虑到,lcm(x,y)==x*y/gcd(x,y)
枚举i==gcd(x,y),对于每个i,
找到其倍数里出现的最小的两个x、y,
这个是埃筛的操作,j+=i的时候会遍历到i的倍数,
取到两个就break就好,毕竟更大的x、y,
对于固定下来的gcd来讲,答案不会更优
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn=1e7+10;
int n,v;
int pos[maxn];//每个值出现的位置
ll ans;
int ai,aj;
int main()
{
scanf("%d",&n);
ans=1e18;
for(int i=1;i<=n;++i)
{
scanf("%d",&v);
if(pos[v]&&ans>v)
ans=v,ai=pos[v],aj=i;
pos[v]=i;
}
for(ll i=1;i<maxn;++i)
{
ll first=-1;
for(ll j=i;j<maxn;j+=i)
{
if(pos[j])
{
if(first==-1)first=j;//第一个值ai
else //第二个值aj
{
if(ans>first*j/i)
ans=first*j/i,ai=pos[first],aj=pos[j];
break;//找到最小的两个 满足gcd(ai,aj)==i;
}
}
}
}
if(ai>aj)swap(ai,aj);
printf("%d %d\n",ai,aj);
return 0;
}