X的因子链(筛质数、分解质因数、组合计数)————《信息学奥赛一本通》 , POJ
作者:互联网
输入正整数 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因子中已经不可再分的了,把X拆分成质数的乘积后,可以保证序列的长度最长,序列的最长长度就是质因子的个数
求序列的数量:
如果质因子乘的次序不同,序列也会不同,因为质因子可能会有重复,
因此可以用排列组合的知识(多重集合的排列问题),
序列的个数=用质因子个数的阶乘除以各个质因子重复出现次数的阶乘
比如 2 ∗ 2 ∗ 2 ∗ 3 ∗ 3 ∗ 4 = 288 2*2*2*3*3*4 = 288 2∗2∗2∗3∗3∗4=288, 质因子数量总共是6, 2有三个,3有两个,4有1个,因此序列的最长长度为6,序列的数量= 6!/(3!*2!)
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
/*
*/
const int N = (1<<20)+5;
typedef long long LL;
int primes[N],cnt;
bool st[N];
int min_fact[N]; //min_fact[i]存储i的最小质因数
void get_primes(int n)
{
for(int i=2; i<=n; ++i){
if(!st[i]){
primes[cnt++] = i;
min_fact[i] = i;
}
for(int j=0; primes[j]*i<=n; ++j)
{
st[primes[j]*i] = true;
min_fact[primes[j]*i] = primes[j];
if(i%primes[j] == 0) break;
}
}
}
int sum[N]; //记录每个质因子出现的次数
int main()
{
get_primes(N-1);
int n;
while(scanf("%d",&n)!=EOF)
{
int k = 0, tot = 0; //tot存储最大长度,k存储质因子数量
while(n>1)
{
int p = min_fact[n];
sum[k] = 0;
while(n%p==0){
sum[k]++;
tot++;
n/=p;
}
k++;
}
LL res = 1;
for(int i=2; i<=tot; ++i)
res *= i;
for(int i=0; i<k; ++i){
for(int j=1; j<=sum[i]; ++j){
res /= j;
}
}
printf("%d %lld\n",tot,res);
}
return 0;
}
标签:int,质数,因子,POJ,奥赛,序列,长度,primes 来源: https://blog.csdn.net/qq_26139541/article/details/121567429