codeforces#1154G. Minimum Possible LCM(最小公倍数)

题目链接:

http://codeforces.com/contest/1154/problem/G

题意:

有n个数,每个数的值为$a_i$

找到一个最小的$lcm(a_i, a_j)$并且满足$1 \le i < j \le n$

数据范围:

$2 \le n \le 10^6$
$1 \le a_i \le 10^7$

分析: 

错误想法1,用每个$a_i$去找倍数,然后找到最小的数,它是两个数的倍数。错在最小公倍数可能很大。这样枚举会超时。

错误想法2,分解每个$a_i$,在每个因数里面找最小的两个数。同样,因为复杂度为$O\left ( m^{3/2} \right )$,超时

正确解法:枚举$x$从1到$m$作为因数,遍历1到m的所有$x$的倍数。如果存在两个数都是$x$的倍数,那么最小的两个数可以取得最大公因数为$x$的最小公倍数

ac代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e6+10;
const int maxm=1e7+10;
int pos[maxm];
ll ans=1e18;
int ansl,ansr;
vector<int>ve;
int main()
{
    int n;
    scanf("%d",&n);
    for(int i=1; i<=n; i++)
    {
        int x;
        scanf("%d",&x);
        if(pos[x]&&ans>x)
        {
            ans=x;
            ansl=pos[x],ansr=i;
        }
        pos[x]=i;
    }
    for(int i=1; i<=maxm; i++)
    {
        ve.clear();
        for(int j=i; j<=maxm; j+=i)
        {
            if(pos[j])
            {
                ve.push_back(j);
                if(ve.size()==2)break;
            }
        }
        if(ve.size()==2)
        {
            if(ans>(ll)ve[0]*ve[1]/i)
            {
                ans=(ll)ve[0]*ve[1]/i;
                ansl=pos[ve[0]];
                ansr=pos[ve[1]];
            }
        }
    }
    if(ansl>ansr)swap(ansl,ansr);
    printf("%d %d\n",ansl,ansr);
    return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/carcar/p/10770091.html