X的因子链(筛质数、分解质因数、组合计数)————《信息学奥赛一本通》 , POJ

X的因子链

输入正整数 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 222334=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;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

葛济维的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值