POJ 3421 X-factor-Chains

题目要求找到正整数X的最长X因子链及其数量,链中每个数字都小于其后一个且能整除它。通过质因数分解和排列组合计算解题。优化算法时注意到只需对X的平方根进行素数筛并分解质因数,可大大提高效率。
摘要由CSDN通过智能技术生成

Given a positive integer X, an X-factor chain of length m is a sequence of integers,

1 = X0, X1, X2, …, Xm = X

satisfying

Xi < Xi+1 and Xi | Xi+1 where a | b means a perfectly divides into b.

Now we are interested in the maximum length of X-factor chains and the number of chains of such length.

Input

The input consists of several test cases. Each contains a positive
integer X (X ≤ 220).

Output

For each test case, output the maximum length and the number of such X-factors chains.

Sample Input

2
3
4
10
100

Sample Output

1 1
1 1
2 1
2 2
4 6

这个题就是让求,把一个数字因数分解,将因数写成一列,要求后一个数字能被前一个数字整除。问这样的因子链中最长的链有多少个。
做法就是将该数字因式分解,分解成质因子。所有的质因子相乘能得到这个数字。那么只取其中的一些因子相乘也必定能整除这个数。
像 100 可以分解为 2*2*5*5
就可以写成 2-(2*2)-(2*2*5)-(2*2*5*5) 这样一条链
然后排列组合算种类数
所以最终是求一个数的不重复的质因子的全排列。

最开始看到给的数据范围是2^20次方,然后傻傻的建了一个很大的数组晒素数。。。肯定筛不出来的。。。后来才想到,因式分解,最多只要除到这个数的平方根就好了,根本不用筛那么多素数,,,TAT。。。
所以这个题只要筛到2^10=1024就够了,,,建个1100的数组就够用了。
在分解质因数的时候,也要注意遍历的范围停止条件,缩小范围。
这样会快很多。

#include<iostream>
#include<cstring>
#include<map>
#define SIZE 11000
using namespace std;
long long p[SIZE + 1];

void prime()//筛素数
{
    int i, j, k, t;
    memset(p, 0, sizeof(p));
    for (i = 2; i <= SIZE; i++)
    {
        if (!p[i])
            for (j = i + 1; j <= SIZE; j++)
                if (j%i == 0) p[j] = 1;
    }
}

long long d(int n)//阶乘
{
    long long sum = 1;
    for (int i = n; i > 0; i--)
        sum *= i;
    return sum;
}

void f(int n)
{
    int i, ct;
    long long sum;
    int s = n;
    map<int, int> a;//存储素因数的个数
    map<int, int>::iterator it;
    ct = 0;
    while (s % 2 == 0)//只有2是偶素数先把偶数筛掉,后面只用筛奇数,i=i+2,比较快
    {
        ct++;
        if (a[2])
            a[2]++;
        else a[2] = 1;
        s /= 2;
    }
    for (i = 3; i*i <= s&&i <= SIZE;)//奇素数
    {
        if (!p[i])
        {
            if (s%i == 0)
            {
                s /= i;
                if (a[i])
                    a[i]++;
                else a[i] = 1;
                ct++;
            }
            else i = i + 2;
        }
        else i = i + 2;
    }
    if (s != 1)
    {
        ct++;
        if (a[s])
            a[s]++;
        else a[s] = 1;
    }
    for (it = a.begin(), sum = 1; it != a.end(); it++)
        sum *= d(it->second);
    cout << ct << " " << d(ct) / sum << endl;
}

int main()
{
    int T;
    int i, j, k, t;
    bool flag;
    prime();
    while (cin >> T)
    {
        flag = false;
        for (i = 2; i <= SIZE&&i*i <= T&&flag == false; i++)
        {
            if (T%i == 0)
            {
                f(T);//不是素数
                flag = true;
                break;
            }
        }
        if (flag == false && T != 1)//是素数
            cout << "1 1" << endl;
        else if (flag == false && T == 1)//该数字为1
            cout << "0 1" << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值