題面

題目鏈接
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; }
