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

相關文章
相關標籤/搜索