Codeforces Round #552 (Div. 3) G.Minimum Possible LCM(数论-埃筛+枚举gcd)

题目

给你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;
}

猜你喜欢

转载自blog.csdn.net/Code92007/article/details/89364614