Codeforces Round #641 (Div. 2) C

Codeforces Round #641 (Div. 2) C

数论
很有意思的一道题,有一说一
–>Link

C. Orac and LCM

  • 题意:给你一个长为n的数串,它们之间两两取lcm得到一个新的数串,再取总gcd,求所得答案

  • 思路:(我太菜了,我觉得很难,但是的确很有意思,参考了一些大佬的解析,我决定自己写一个)

    • 基础补充:
      对于任意一个数,可以表示成为: x = p 1 a 1 ∗ p 2 a 2 ∗ . . . ∗ p n a n ; x=p_1^{a_1}*p_2^{a_2}*...*p_n^{a_n}; x=p1a1p2a2...pnan; y = p 1 b 1 ∗ p 2 b 2 ∗ . . . ∗ p n b n ; y=p_1^{b_1}*p_2^{b_2}*...*p_n^{b_n}; y=p1b1p2b2...pnbn;
      而对于gcd,lcm: l c m ( x , y ) = p 1 m a x ( a 1 , b 1 ) ∗ p 2 m a x ( a 2 , b 2 ) ∗ . . . ∗ p n m a x ( a n , b n ) lcm(x , y)=p_1^{max(a_1,b_1)}*p_2^{max(a_2,b_2)}*...*p_n^{max(a_n,b_n)} lcm(x,y)=p1max(a1,b1)p2max(a2,b2)...pnmax(an,bn) g c d ( x , y ) = p 1 m i n ( a 1 , b 1 ) ∗ p 2 m i n ( a 2 , b 2 ) ∗ . . . ∗ p n m a x ( a n , b n ) gcd(x , y)=p_1^{min(a_1,b_1)}*p_2^{min(a_2,b_2)}*...*p_n^{max(a_n,b_n)} gcd(x,y)=p1min(a1,b1)p2min(a2,b2)...pnmax(an,bn)
      究其本质后,就好做了。
  • 解题:那么,开始求lcm的时候,就是两两之间求幂次的最大,再求gcd的时候,就是所有数(lcm过后)中每个质数幂次的最小。(不理解的话其实可以随便举两个数,去套入上面的gcd、lcm公式去算一两遍就好多了)
    对于任意一个质因子: p i p_i pi化成单个来理解,它的幂次(lcm之前)分别为: a i , b i , c i . . . ( 不 排 除 0 ) a_i,b_i,c_i...(不排除0) ai,bi,ci...0在其中两两求取最大值,再在其中求最小值,就是该质数对答案的贡献了。
    现在就是要从原始数组里直接找到最后的最小值。

    那我们开始考虑,对于这个质因子(设为x)来说:

  1. 如果原始数列所有数都包含了该质因子:
    那么对于这个因子,它在所有数上的幂次都大于0(因为都出现了),两两求取幂次的最大值后,再求其中的最小值,其中最小值即为:pri[ x ][ 1 ]
    则ans*=qpow( x , pri[x][1])

    pri意为质数x在所有数中出现的幂次,1为第二小的幂次

    为什么是第二小?

    在x出现的所有幂次中,两两取最大值后,其中的最小值即为原数组最小,和第二小的两数取max,取得的值为第二小的值。

  2. 若该质因子仅被包含n-1次,那么有一个数会不包含因子x。相当于在这里幂数取了0。那么在两两取最大值后,其中的最小值即为原数组最小,和这个0的两数的max,取得的值为最小值
    则ans*=qpow( x ,pri[ x ][ 0 ])

  3. 若小于n-1次,同理,至少会有两个数包含x的幂次是0,那么最小值是0,对答案无贡献,不考虑这个情况。

  • 综上:
    对每个数进行质因分解,并且求的每个质数的幂次。
    对每个质数的幂次排序
    对于每个质数,数它在数列中出现的次数
    1. 若为n次,它对答案的贡献是:x的倒数第二大幂次次方
    2. 若为n-1次,它对答案的贡献是:x的最小幂次次方
    3. 否则,不考虑

DONE

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#pragma warning(disable:4996)
#define inf 0x3f3f3f3f
#define linf 0x3f3f3f3f3f3f3f
#define itn int
#define ll long long
#define mes(a,k) memset(a,k,sizeof(a))
//#define max(a,b) a>b?a:b
//#define min(a,b) a pri[N];//pri[i][j]表示:质数i在各个数中出现的幂数,j仅作为下标
int cnt[N];//质数i在所有的数中出现的次数(可用pri[i].size()代替)
void io() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); }
ll qpow(ll a, ll b) {//快速幂捞一下
	ll ans = 1;
	while (b) {
		if (b & 1) {
			ans *= a;
		}
		a *= a;
		b >>= 1;
	}
	return ans;
}
int main() {
	io();
	int T;
	cin >> T;
	for (int i = 0; i < T; ++i) {
		int x;
		cin >> x;
		for (int j = 2; j * j <= x; ++j) {//找出质因子
			if (x % j == 0) {
				cnt[j]++;
				int po = 0;
				while (x % j == 0) {
					x /= j;
					po++;
				}
				pri[j].push_back(po);
			}
		}
		if (x != 1) {
			cnt[x]++;//我是我自己
			pri[x].push_back(1);
		}
	}
	ll ans = 1;
	for (int i = 1; i <= N-3; i++) {
		if (cnt[i] >= T - 1) {
			sort(pri[i].begin(), pri[i].end());
			if (cnt[i] == T - 1)
				ans *= qpow(i,pri[i][0]);//若是T-1,则取幂数最小
			else
				ans *= qpow(i,pri[i][1]);//是T(全勤),则取幂数第二小
		}
	}
	cout << ans << endl;
	return 0;
}

你可能感兴趣的:(Codeforces,数论)