poj 3421 X-factor Chains

缘起

日常浪费生命 poj 3421 X-factor Chains

分析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
给定一个正整数X,长为m的因子链定义为长度为m的如下序列
1 = X0, X1, X2, …, Xm = X
并且满足
Xi < Xi+1 && Xi | Xi+1
现在要求因子链最长能有多长(长度记为m), 并且求长度为m的因子链的个数.

【输入】
多样例,每行一个X(<=2^20)

【输出】
对每个样例,输出最长长度,以及该长度下不同因子链的个数

【样例输入】
2
3
4
10
100

【样例输出】
1 1
1 1
2 1
2 2
4 6

【限制】
1s

数学题. 都是些简单的高中排列组合知识

1
2
3
4
 如果X分解素因数为
X = e1^f1*e2^f2*....*en^fn
的话, 则最长为 m=f1+f2+...+fn
并且不同的长度为m的因子链的个数是 m!/(f1!*f2!*...*fn!)

那使用什么算法分解素因数呢? 因为X<=2^20, 所以开方之后<=2^10=1024, 我们完全可以使用线性筛先把1024范围内的素数筛出来(大约168个). 然后对每个X,用不超过sqrt(X)的素数按照从小到大的顺序去整除. 一旦能整除, 就发现了一个X的最小的素因子p. 然后把X的p全部剥离出来. 得到的剩下的X再使用p之后的不超过sqrt(X)的素数去整除. 直至不超过sqrt(X)的素数全部执行完毕, 则剩下的X如果还>1的话, 就是一个素数(这个素数大于sqrt(X)),则得到了X的分解素因数情况. 一旦得到了分解素因数的情况,m就呼之欲出了. 但是如何计算m!/(f1!*f2!…\fn!)

这个我们必须要谨慎对待,一不小心就溢出了. 首先,为了快速计算, f1,…,fn要升序排序(这样后面的可以利用到前面的计算结果)。 然后,我们知道任何连续n个正整数的乘积一定是n!的倍数。所以计算该表达式的算法也就呼之欲出了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//#include "stdafx.h"

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
//#define LOCAL
typedef unsigned long long ULL;

int x, p[1028], num,num1, f[1024]; // f用于存储各个素因子的幂次 num1是x分解素因数得到的素因子的个数,p和num用于存储1024之前的素数
bool isp[1028];

void sieve()
{
memset(isp, true, sizeof(isp));
for (int i = 2; i<1028; i++)
{
if (isp[i])
{
p[num++] = i;
for (int j = (i<<1); j<1028; j+=i)
{
isp[j] = false;
}
}
}
}

int main()
{
#ifdef LOCAL
freopen("d:\\data.in", "r", stdin);
// freopen("d:\\my.out", "w", stdout);
#endif
sieve(); // 筛出1024以内的全部素数——p[0,...,num-1]
while(~scanf("%d", &x))
{
int tot =0;//最长的m
num1 = 0;
for (int i = 0; i<num; i++)
{
if (!(x%p[i])) // 如果p[i]是x的素因子
{
f[num1] = 0;
while(x>1&&!(x%p[i])) // 只要x大于1并且还是p[i]的倍数
{
x/=p[i];
f[num1]++;
} // 最后要么x=1要么x不能整除p[i]了
tot+=f[num1];
num1++;
if (x==1) // 如果最后x变成了1,则跳出
{
break;
}
}
}
if (x>1)
{
f[num1] = 1;
tot+=1;
num1++;
}
sort(f, f+num1); // 从低到高排序
ULL ans = 1, anss = 1;
for (int i = 0,x=1,t=1; i<num1; i++)
{
for (int j = 1;j<=f[i]; j++,x++)
{
ans*=x;
}
for (; t<=f[i]; t++)
{
anss*=t;
}
ans/=anss;
}
printf("%d %llu\n", tot, ans);
}
return 0;
}
Status Accepted
Time 47ms
Memory 104kB
Length 1271
Lang C++
Submitted 2019-09-01 10:12:48
Shared
RemoteRunId 20822883