CF1154G Minimum Possible LCM

题意

给出一个长度为$n$的序列$a$,找到一组下标$i,j$,使它们的$lcm(a_i,a_j)$最小。

 

$zszz,lcm(a_i,a_j)=\frac{a_i\times a_j}{gcd(a_i,a_j)}$

考虑枚举下方$gcd$,计算最小的两个是$gcd$倍数的$lcm$。

设$Max=\sum_{i=1}^{n}max(a_i)$,计算次数最劣为$\sum_{i=1}^{n}\lceil\frac{Max}{i}\rceil$,为调和级数。

$1.8\times 10^{8}$左右,$4s$能过。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxm=1e6+5,maxn=1e7+5;
int n,a[maxm],mapp[maxn],Max,pos1,pos2;
ll ans=1e18;
int main() {
	scanf("%d",&n);
	for(int i=1;i<=n;++i) scanf("%d",&a[i]),mapp[a[i]]++,Max=max(Max,a[i]);
	for(int i=1;i<=n&&i<=ans;++i) {
		if(mapp[i]>1&&ans>i) {
			pos1=pos2=i;
			ans=i;
		}
		int js=0;
		ll wz=0;
		for(int j=1;i*j<=Max;++j) {
			if(mapp[i*j]) {
				if(js||mapp[i*j]>1) {
					if(js) {
						ll temp=wz*i*j;
						if(temp<ans) {
							pos1=wz*i,pos2=i*j;
							ans=temp;
						}
					}
					break;
				}
				else js++,wz=j;
			}
		}
	}
	if(pos1==pos2) {
		int js=0;
		for(int i=1;i<=n&&js<=1;++i) if(a[i]==pos1) printf("%d ",i);
		putchar('\n');
	}
	else {
		for(int i=1;i<=n;++i) if(a[i]==pos1) {pos1=i;break;}
		for(int i=1;i<=n;++i) if(a[i]==pos2) {pos2=i;break;}
		if(pos1>pos2) swap(pos1,pos2);
		printf("%d %d\n",pos1,pos2);
	}
	return 0;
}

 

posted @ 2021-01-18 09:45  Kaiser_Kell  阅读(58)  评论(0编辑  收藏  举报