题目描述
输入正整数 X,求 X 的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。
输入格式
输入包含多组数据,每组数据占一行,包含一个正整数表示 X。
输出格式
对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。
每个结果占一行。
数据范围
1≤X≤220
输入样例:
2
3
4
10
100
输出样例:
1 1
1 1
2 1
2 2
4 6
分析
由唯一分解定理可知, 任意一个数 X X X都可以分解成 X = p 1 k 1 ∗ p 2 k 2 ∗ . . . ∗ p n k n X = p_1^{k_1}*p_2^{k_2}*...*p_n^{k_n} X=p1k1∗p2k2∗...∗pnkn(其中 p 1 < p 2 < . . . < p n , 且 p 1 , p 2 , . . . , p n 为 质 数 p_1<p_2<...<p_n,且p_1,p_2,...,p_n为质数 p1<p2<...<pn,且p1,p2,...,pn为质数)
题目要求的序列为 X X X的大于 1 1 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度
由于序列是由 X X X的因子组成, 所以容易满足前一项整除后一项, 且严格递增
接下来考虑这样的序列的最大长度是多少?
观察 X = p 1 k 1 ∗ p 2 k 2 ∗ . . . ∗ p n k n X = p_1^{k_1}*p_2^{k_2}*...*p_n^{k_n} X=p1k1∗p2k2∗...∗pnkn, 不难发现在满足整除和递增的条件下,
每次 后 一 项 = 前 一 项 ∗ p s ( p s 为 X 中 剩 余 的 最 小 的 质 因 子 ) 时 后一项 = 前一项 *p_s(p_s为X中剩余的最小的质因子)时 后一项=前一项∗ps(ps为X中剩余的最小的质因子)时,得到的序列长度最长
(假如 p s p_s ps不是当前最小的质因子, 则 p s p_s ps一定可以再分解成 p m ∗ p n p_m*p_n pm∗pn, 则这样的序列长度并不是最长)
所以最长序列的长度为 k 1 + k 2 + . . . + k n k_1 + k_2 + ... + k_n k1+k2+...+kn, 个数为 ( k 1 + k 2 + . . . + k n ) ! k 1 ! k 2 ! . . k n ! \frac{(k_1 + k_2 + ... + kn)!}{k_1!k_2!..k_n!} k1!k2!..kn!(k1+k2+...+kn)!(有重复数集合的排列数)
对于每个数 X X X的最小质因子,我们可以用线性筛
筛选出来
实现
#include <cstdio>
#include <iostream>
using namespace std;
const int N = (1 << 20) + 9;
int x;
int primes[N]; // 记录质数
int minp[N]; // 记录质因子
bool st[N]; // st[i] = 0 表示 i 是 质数
int cnt[N]; // 记录数x的每个质因子的数量
void getPrimes() // 筛出质数, 以及每个数的最小质因子
{
int cnt = 0;
for(int i=2; i<= 1 << 20; i++)
{
if(!st[i])
{
primes[cnt++] = i;
minp[i] = i;
}
for(int j=0; i*primes[j] <= 1 << 20; j++)
{
st[i * primes[j]] = true;
minp[i * primes[j]] = primes[j];
if(i % primes[j] == 0) break;
}
}
}
int main()
{
getPrimes();
while(cin >> x)
{
int k = 0; // 记录数x质因子p的数量
int total = 0; // 记录数X质因子的个数
long long ans = 1;
// 分解质因子
while(x > 1)
{
int p = minp[x];
cnt[k] = 0; // 不要使用memset, 复杂度太高
while(x % p == 0)
{
x /= p;
cnt[k]++;
total++;
}
k++;
}
for(int i=1; i<=total; i++) ans *= i; // total的阶乘
for(int i=0; i<k; i++) // 除以每个质因子数量的阶乘
{
for(int j=1; j<=cnt[i]; j++)
{
ans /= j;
}
}
cout << total << " " << ans << endl;
}
return 0;
}