X的因子链
X的因子链
输入正整数 $X$,求 $X$ 的大于 $1$ 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。
输入格式
输入包含多组数据,每组数据占一行,包含一个正整数表示 $X$。
输出格式
对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。
每个结果占一行。
数据范围
$1 \leq X \leq 2^{20}$
输入样例:
2 3 4 10 100
输出样例:
1 1 1 1 2 1 2 2 4 6
解题思路
在递增的序列中,要求每一项比前一项要大,并且前一项要整除后一项,即$a_{i} | a_{i + 1}$。意味着$a_{i + 1} = a_{i} \times k$,$k$为倍数,且$k > 1$。为了让整个序列尽可能长,我们应该要让这个倍数$k$尽可能小。$k$最小最小只能是一个质数,因为质数不可以再分了,而合数还可以继续分。例如当前有$a_{i + 1} = a_{i} \times 6$,那么必然可以变成$a_{i}, a_{i} \times 2, a_{i + 1}, ......$或者$a_{i}, a_{i} \times 3, a_{i + 1}, ......$。
因此可以用素数分解定理,假设$X$分解质因数后的结果是$X = P_{1}^{\alpha_{1}} \cdot P_{2}^{\alpha_{2}} \cdot \cdots \cdot P_{n}^{\alpha_{n}}$,一共有$\alpha_{1} + \alpha_{2} + \cdots + \alpha_{n}$个质因子。因此我们每一次乘的倍数必然是当中的一个质因子(不包括$1$)。我们每次要乘一个质因子,最多可以乘$\alpha_{1} + \alpha_{2} + \cdots + \alpha_{n}$个质因子,因此整个序列的最大长度就是$\alpha_{1} + \alpha_{2} + \cdots + \alpha_{n}$。
下面要考虑的是如何求这个长度的序列的个数有多少个。因为我们每次在前面一个数的基础上,都可以从中任选其中一个之前未选的质因数来乘,因此会有多种选择。
假设每一个质因数都不同,那么我们有$\left( {\sum\limits_{i = 1}^{n}\alpha_{i}} \right)!$种选法。又因为每个质因数可能包含多个,对应着$\alpha_{i} > 1$。因为我们要求的是有多少组不同的选法,直接用$\left( {\sum\limits_{i = 1}^{n}\alpha_{i}} \right)!$来求的话会包含重复的组。那么一组中会重复多少次呢?答案是$\prod\limits_{i = 1}^{n}{\alpha_{i}!}$。这是因为在每组选择中,$P_{i}$都会有$\alpha_{i}$个,他们都是重复的,对应的重复次数为$\alpha_{i}!$次,因此对于某一组,所有的$P_{i}$会重复$\prod\limits_{i = 1}^{n}{\alpha_{i}!}$次。因此实际上一共有$\frac{\left( {\sum\limits_{i = 1}^{n}\alpha_{i}} \right)!}{\prod\limits_{i = 1}^{n}{\alpha_{i}!}}$个不同的组。
其中$$\frac{\left( {\sum\limits_{i = 1}^{n}\alpha_{i}} \right)!}{\prod\limits_{i = 1}^{n}{\alpha_{i}!}}$$又被称为多重集的排列数问题。
AC代码如下:
1 #include2 #include 3 using namespace std; 4 5 const int N = (1 << 20) + 10; 6 7 int primes[N], cnt; 8 bool vis[N]; 9 int minp[N]; // 存放每一个数的最小质数 10 11 void get_prime(int n) { 12 for (int i = 2; i <= n; i++) { 13 if (!vis[i]) { 14 primes[cnt++] = i; 15 minp[i] = i; 16 } 17 for (int j = 0; primes[j] <= n / i; j++) { 18 vis[primes[j] * i] = true; 19 minp[primes[j] * i] = primes[j]; 20 if (i % primes[j] == 0) break; 21 } 22 } 23 } 24 25 int main() { 26 get_prime(1 << 20); // 直接分解每一个数可能会超时,因此先筛质数,通过每一个的最小质数来分解质因数 27 28 int n; 29 while (~scanf("%d", &n)) { 30 int a[20] = {0}, m = 0, sum = 0; // 不同质因子的个数不会超过10个,可以估计出来 31 while (n > 1) { 32 int p = minp[n]; 33 while (minp[n] == p) { 34 a[m]++; 35 sum++; 36 n /= minp[n]; 37 } 38 m++; 39 } 40 41 long long ret = 1; 42 for (int i = 1; i <= sum; i++) { 43 ret *= i; 44 } 45 for (int i = 0; i < m; i++) { 46 for (int j = 1; j <= a[i]; j++) { 47 ret /= j; 48 } 49 } 50 printf("%d %lld\n", sum, ret); 51 } 52 53 return 0; 54 }
参考资料
AcWing 1295. X的因子链(蓝桥杯C++ AB组辅导课):https://www.acwing.com/video/745/