Codeforces B. Minimum Possible LCM(贪心数论)

题目描述:

B. Minimum Possible LCMios

time limit per test算法

4 secondsthis

memory limit per testspa

1024 megabytes.net

inputcode

standard inputblog

outputip

standard outputci

You are given an array aconsisting of integers a1,a2,…,*a**n*element

Your problem is to find such pair of indices i,j that lcm(\(a_i\),\(a_j\))is minimum possible.

lcm(x,y) is the least common multiple of and x and y(minimum positive number such that both x and y are divisors of this number).

Input

The first line of the input contains one integer n — the number of elements in a

The second line of the input contains n integers a1,a2,…,an (1≤ai≤107), where ai is the i-th element of a.is the i.

Output

Print two integers i and (1≤i<jn is minimum among all valid pairs i,j

思路:

题目是要求一组数中两个数的最小公倍数的最小值。刚开始一个直白的想法就是枚举,把每两个数的gcd求出来,根据gcd求每两个数的lcm。这种作法的时间复杂度为O(\(n^2\log_2 n\)),在看看题目的数据范围,显然不太科学,限时4秒,\(10^{12}log_210^{6}\),会远远超时。怎么办?

咱们来想想,通常lcm问题与gcd问题是挂钩的。怎么样来求,因为数据的范围给定了,考虑枚举数的因子,从1开始到\(10^7\),在数列中找到一因子为最大公约数的两个最小数,就是答案。为何?

假设如今枚举到了公因子d,数列中是d的倍数的有\(x_1\)<\(x_2\)<\(x_3\)<...<\(x_n\),若是d是\(x_1\),\(x_2\)的gcd,那么也就知足条件,x1,x2的最小公倍数确定最小(在d为因子时)。若是d不是x1,x2的gcd,那也不是后面数的gcd,那么最大公倍数就不会最小。

因为d是从小到大枚举的,若是在d时知足条件,确定为局部最优解。若是都不知足d为gcd,d++,继续枚举直到知足。因为算法必定会终止,算法的正确性就有了保障。算法复杂度是O(\(n\log_2 n\))

须要注意的是当元素有重复的状况,那么这种元素的最小公倍数就是自己,并且只多是最小重复元素的时候,由于若是比它大的重复元素的lcm必定大于它,不会是全局最小lcm,单独在输入的时候不断覆盖,留下最小的一种便可。

注意LLONG_MAX和LONG_MAX是不同的,我一开始错了,原来由于是数不够大。

代码:

#include <iostream>
#include <climits>
#define INF LLONG_MAX
#define max_n 10000007
using namespace std;
long long a[max_n];
int n;
int pos[max_n];
long long ans = 0;
long long minm = INF;
int x = 0;
int y = 0;
long long gcd(long long a,long long b)
{
    return (b==0)?a:gcd(b,a%b);
}
int main()
{
    cin >> n;
    for(int i = 1;i<=n;i++)
    {
        int v;
        cin >> v;
        a[v]++;
        if(a[v]>1&&v<minm)
        {
            minm = v;
            x = pos[v];
            y = i;
        }
        pos[v] = i;
    }
    for(int i = 1;i<max_n;i++)
    {
        long long v = 0;
        for(int j = i;j<max_n;j+=i)
        {
            if(a[j]==0)
            {
                continue;
            }
            if(v==0)
            {
                v = j;
            }
            else
            {
                long long g = gcd(v/i,j/i);
                if(g==1)
                {
                    ans = (long long)j/i*v;
                    if(ans<minm)
                    {
                        //cout << "v " << v << " j " << j << endl;
                        minm = ans;
                        x = pos[v];
                        y = pos[j];
                    }
                }
                break;

            }
        }
    }
    if(x>y) swap(x,y);
    cout << x <<  " " << y << endl;
    return 0;
}

参考文章:

KobeDuu,Minimum Possible LCM【枚举】,https://blog.csdn.net/qq_41157137/article/details/89353527

相关文章
相关标签/搜索