Orac and LCM


題面

 

題目鏈接

 

https://codeforces.com/contest/1349/problem/A

 

題目大意

 

給你一個長度為 N 的數組,求 gcd {lcm({ai , aj}) | i < j} 

 

解題思路

 

這道題有兩種解法

① :

對於 a1 , 產生的 lcm 為 lcm(a1 , a2) , lcm(a1 , a3) ... lcm(a1 , an)

產生的 gcd_1 為 gcd ( lcm(a1 , a2) , lcm(a1 , a3) ... lcm(a1 , an) ) 

因為參與 gcd_1 的每一項都是 a1 的倍數

所以 gcd( lcm(a1 , a2) , lcm(a1 , a3) ... lcm(a1 , an) ) 可以化為 lcm (a1 , gcd (a2 , a3 , ... an) )

那么最后答案就為 ans = gcd( gcd_1 , gcd_2 , ... gcd_n )  , 我們維護一個后綴就可以搞定了

② : 

假設 ai 沒有 2 這個因子,且 aj 也沒 2 這個因子,那么 lcm(a[i] , a[j]) 就不包含 2 這個因子

那么 ans = gcd {lcm({ai , aj}) | i < j} 也就不包含 2 這個因子 

也就是說數組中如果有兩個以上的數都不包含某個因子,那么答案也就不包含這個因子

所以我們可以對每個質因子開個容器,然后對每個數進行質因子分解

並將分解后質因子的冪次存於對應質因子的容器中

然后計算答案時判斷每個質因子的容器大小是否大於等於 N - 1

如果是則說明數組中少於兩個數沒有這個質因子,則答案必定要乘上這個質因子

至於是該乘上這個質因子的幾次方,我們對容器升序排個序

如果容器的大小等於 N 則取第二個元素次小冪次,如果等於 N - 1則取第一個元素最小冪次

以某質數容器的大小為 N 舉例 :

最后一個元素對應最大冪次,只有一個數包含了這個它,倒數第二個元素對應次大冪次,有兩個數包含了它

以此類推第二個元素對應次小冪次,有 N - 1 個數包含了它,第一個元素為最小次冪,有 N 個數包含了它

因為只需要 N - 1個數有包含它答案就可以乘上它,所以我們選第二個元素作為冪次

(這里次小不是嚴格意義上的次小,即 最小 <= 次小)

 

AC_Code ①

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N = 3e5 + 10;
int gcd(int a , int b)
{
    return b ? gcd(b , a % b) : a;
}
int lcm(int a , int b)
{
    return a * b / gcd(a , b);
}
int a[N] , suf[N];
signed main()
{
    ios::sync_with_stdio(false); 
    int n , ans = 0;
    cin >> n; 
    for(int i = 1 ; i <= n ; i ++) cin >> a[i];
    for(int i = n ; i >= 1 ; i --) suf[i] = gcd(suf[i + 1] , a[i]);
    for(int i = 1 ; i <= n ; i ++) ans = gcd(ans , lcm(a[i] , suf[i + 1]));
    cout << ans << '\n' ; 
    return 0;
}

 

AC_Code ②

#include<bits/stdc++.h>
#define int long long 
using namespace std;
const int N = 2e5 + 10;
int prime[N] , minprime[N];
vector<int>vec[N];
int pow_mod(int x , int n)
{
    int res = 1;
    while(n)
    {
        if(n & 1) res = res * x;
        x = x * x; 
        n >>= 1;
    }
    return res;
}
int euler(int n)
{
    int c = 0 , i , j;
    for(int i = 2 ; i <= n ; i ++ )
    {
        if(!minprime[i]) prime[++ c] = i , minprime[i] = i;
        for(j = 1 ; j <= c && i * prime[j] <= n ; j++)
        {
            minprime[i * prime[j]] = prime[j];
            if(i % prime[j] == 0) break;
        }
    }
    return c;
}
void get_prime(int n)
{
    for(int i = 1 ; i <= n ; i ++)
    {
        int x = prime[i]; 
        if(x * x > n) break ; 
        if(n % x == 0)
        {
            int c = 0;
            while(n % x == 0) n /= x , c ++ ; 
            vec[x].push_back(c);
        }
    }
    if(n > 1) vec[n].push_back(1);
}
signed main()
{
    ios::sync_with_stdio(false);
    int cnt = euler(N - 10);
    int n , x , ans = 1;
     cin >> n;
     for(int i = 1 ; i <= n ; i ++)
     {
         cin >> x; 
         get_prime(x);
    }
    for(int i = 1 ; i <= cnt ; i ++)
    {
        int x = prime[i];
        sort(vec[x].begin() , vec[x].end());
        if(vec[x].size() == n) ans *= pow_mod(x , vec[x][1]);
        else if(vec[x].size() == n - 1) ans *= pow_mod(x , vec[x][0]);
    }
    cout << ans << '\n' ; 
    return 0;
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM