X的因子链

X的因子链

输入正整数 X,求 X 的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。

输入格式

输入包含多组数据,每组数据占一行,包含一个正整数表示 X

输出格式

 对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。

每个结果占一行。

数据范围

1X220

输入样例:

2
3
4
10
100

输出样例:

1 1
1 1
2 1
2 2
4 6

 

解题思路

  在递增的序列中,要求每一项比前一项要大,并且前一项要整除后一项,即ai|ai+1。意味着ai+1=ai×kk为倍数,且k>1。为了让整个序列尽可能长,我们应该要让这个倍数k尽可能小。k最小最小只能是一个质数,因为质数不可以再分了,而合数还可以继续分。例如当前有ai+1=ai×6,那么必然可以变成ai,ai×2,ai+1,......或者ai,ai×3,ai+1,......

  因此可以用素数分解定理,假设X分解质因数后的结果是X=P1α1P2α2Pnαn,一共有α1+α2++αn个质因子。因此我们每一次乘的倍数必然是当中的一个质因子(不包括1)。我们每次要乘一个质因子,最多可以乘α1+α2++αn个质因子,因此整个序列的最大长度就是α1+α2++αn

  下面要考虑的是如何求这个长度的序列的个数有多少个。因为我们每次在前面一个数的基础上,都可以从中任选其中一个之前未选的质因数来乘,因此会有多种选择。

  假设每一个质因数都不同,那么我们有(i=1nαi)!种选法。又因为每个质因数可能包含多个,对应着αi>1。因为我们要求的是有多少组不同的选法,直接用(i=1nαi)!来求的话会包含重复的组。那么一组中会重复多少次呢?答案是i=1nαi!。这是因为在每组选择中,Pi都会有αi个,他们都是重复的,对应的重复次数为αi!次,因此对于某一组,所有的Pi会重复i=1nαi!次。因此实际上一共有(i=1nαi)!i=1nαi!个不同的组。

  其中(i=1nαi)!i=1nαi!又被称为多重集的排列数问题。

  AC代码如下:

复制代码
 1 #include <cstdio>
 2 #include <algorithm>
 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/

posted @   onlyblues  阅读(73)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
历史上的今天:
2021-03-07 在scanf函数中占位符使用错误而产生的一些错误
Web Analytics
点击右上角即可分享
微信分享提示