Orac and LCM(GCD/LCM/质因子分解/推导证明)Codeforces Round #641 (Div. 2) C题

在这里插入图片描述

题目大意

       给 n ( n 100000 ) n(n \le 100000) 个数 a i ( a i 200000 ) a_i(a_i \le 200000) ,求 g c d ( { l c m ( { a i , a j } ) i < j } ) gcd(\{lcm(\{a_i,a_j\})|i<j\}) .

分析过程

       考虑每个数的素因子分解,对于 ( a i , a j ) (a_i,a_j) 的所有组合, l c m ( a i , a j ) lcm(a_i,a_j) 对应的素因子 p k p^k 总满足 k = m a x ( k i , k j ) k=max(k_i,k_j) ,即取二者最大的那一个,而对于 g c d gcd 来说则是取 m i n min 。于是,对于结果 a n s ans 来说,一定有一个唯一的素数分解,其中每一个素数 p k p^k k k 等于所有 l c m ( a i , a j ) lcm(a_i,a_j) 组合中 p p 的最小值,而对于所有 l c m ( a i , a j ) lcm(a_i,a_j) 来说,能够得到的最小值是所有 a i a_i p k p^k 的次小值 k k ,因为最小的那个 k k 肯定会由于 l c m lcm m a x max 特性被掩盖掉,而当最小的 k k 和次小的 k k 对应的 a i a_i 在一起求 l c m lcm 时,次小的那个 k k 对应的 a i a_i 会被保留下来。
       所以,这道题先用类似于埃拉斯托特尼筛选法的方式预处理标记一遍 a i a_i 的最小素因子,然后对于每个 a i a_i 进行素因子分解,然后维护对应素因子的最小值和次小值即可。

Another Solution

       还有一种做法,利用公式 g c d ( l c m ( a 1 , a 2 ) , l c m ( a 1 , a 3 ) . . . l c m ( a 1 , a n ) ) = l c m ( a 1 , g c d ( a 2 , a 3 , . . . a n ) ) gcd( lcm(a1 , a2) , lcm(a1 , a3) ... lcm(a1 , an) ) =lcm (a1 , gcd (a2 , a3 , ... an) )
这样只需要求前缀和后缀 g c d gcd 就行了。
关于这个公式的证明留个坑,等之后来填~!

AC代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
const int N = 200000;
ll flag[N+5], a[maxn], cnt[N+5][3], n;
void preTreat(){
	int i, j;
	for(i=2;i<=N;++i){ //预处理标记每个数能够被整除的最小素因子 
		if(flag[i]) continue;
		for(j=i;j<=N;j+=i){
			if(!flag[j]) flag[j] = i;
		}
	}
	for(i=1;i<=N;++i) cnt[i][0] = cnt[i][1] = N;
}
void solve(){
	int i;
	ll ans = 1;
	for(i=1;i<=n;++i){
		while(a[i] > 1){
			ll c = 0, temp = a[i]; 
			while(a[i] % flag[temp] == 0){
				a[i] /= flag[temp];
				++c;	
			}
			if(c < cnt[flag[temp]][0]) swap(cnt[flag[temp]][0], c);
			if(c < cnt[flag[temp]][1]) swap(cnt[flag[temp]][1], c);
			++cnt[flag[temp]][2]; //记录此因子存在于多少个树中 
		} 
	}
	for(i=2;i<=N;++i){
		if(cnt[i][2] < n - 1) continue;
		ll j = cnt[i][1];
		if(cnt[i][2] == n - 1) j = cnt[i][0];
		while(j--) ans *= i; 
	}
	cout<<ans;
} 
int main(){
	int i;
	ios::sync_with_stdio(false);
	cin>>n;
	for(i=1;i<=n;++i) cin>>a[i];
	preTreat();
	solve();
	return 0;
} 

猜你喜欢

转载自blog.csdn.net/qq_42968686/article/details/106126215