数论-分解质因数-POJ3421-X-factor Chains

时间秒杀一切 提交于 2020-03-01 17:46:34

数论-分解质因数-POJ3421-X-factor Chains

题目:

输入正整数 X,求 X 的大于 1 的因子组成的满足任意前一项都能整除后一项的严格递增序列的最大长度,以及满足最大长度的序列的个数。

输入格式
输入包含多组数据,每组数据占一行,包含一个正整数表示 X。

输出格式
对于每组数据,输出序列的最大长度以及满足最大长度的序列的个数。

每个结果占一行。

数据范围
1≤X≤220
输入样例:
2
3
4
10
100
输出样例:
1 1
1 1
2 1
2 2
4 6

题意:

X p1×p2×...×pnpaaiai+1i>=1,,对给定正整数X,将其分解成\ p_1×p_2×...×p_n的形式,求从序列p的子序列a中,\\满足a_i|a_{i+1},i>=1,且严格单调递增的序列的最大长度是多少,以及最大长度的子序列的个数。

题解:

XX=p1a1×p2a2×...×pnan由唯一分解定理,任意正整数X,都能够分解成几个质因子的幂的积的形式。即X=p_1^{a_1}×p_2^{a_2}×...×p_n^{a_n}。

结论一: :i=1n(ai+1)=(a1+1)(a2+1)...(an+1)约数个数为:\prod_{i=1}^{n}(a_i+1)=(a_1+1)(a_2+1)...(a_n+1)。

X p1b1×p2b2×...×pnbn0<=bi<=ai1<=i<=n,Xn(b1,b2,...,bn)biai+1i=1n(ai+1)理解:X的因子可以表示为\ p_1^{b_1}×p_2^{b_2}×...×p_n^{b_n},其中0<=b_i<=a_i,1<=i<=n,\\对X的幂次n元组(b_1,b_2,...,b_n),每一个b_i都有a_i+1种取值,所以共有\prod_{i=1}^{n}(a_i+1)个约数。

结论二: i=1nj=0aipj=(p0+p1+...+pa1)(p0+...+pa2)...(p0+...+pan)约数之和:\prod_{i=1}^{n}\sum_{j=0}^{a_i}p^j=(p^0+p^1+...+p^{a_1})(p^0+...+p^{a_2})...(p^0+...+p^{a_n})。

理解:式子展开即所有因数之和。

回到本题:

X=p1a1×p2a2×...×pnann(b1,b2,...,bn)0<=bi<=aixixi1pii[1,n]1(a1+a2+...+an)i=1nai对于X=p_1^{a_1}×p_2^{a_2}×...×p_n^{a_n},对n元组(b_1,b_2,...,b_n),0<=b_i<=a_i,\\最长的递增子序列中的每一项x_i一定是在前一项x_{i-1}的基础上乘上p_i的一次方,i∈[1,n]。\\从1递增到(a_1+a_2+...+a_n),最大长度即\sum_{i=1}^{n}a_i。

n(b1,b2,...,bn)xi1=p1b1×p2b2×...×pnbnxi=p1b1×p2b2×...×pjbj+1...×pnbnxixi1 pj,(1<=j<=n)bj+1<=aj反应到n元组(b_1,b_2,...,b_n)上:假设x_{i-1}=p_1^{b_1}×p_2^{b_2}×...×p_n^{b_n},则x_i=p_1^{b_1}×p_2^{b_2}×...×p_j^{b_j+1}...×p_n^{b_n}。\\也就是说x_i在x_{i-1}的基础上乘上了一个质因子\ p_j,(1<=j<=n),且b_j+1<=a_j。

xi>1x0=(0,0,...,0)x1x0,a1+a2+...anx1n(a1+a2+...+an)x2x1x1"1"x1(a1+a2+...+an)!因为质因子x_i>1,从x_0=(0,0,...,0)开始,x_1在x_0的基础上选择,共有a_1+a_2+...a_n个质因子,\\则x_1的n元组共有(a_1+a_2+...+a_n)种选择。\\同理,x_2就在x_1的基础上选择,在x_1的基础上增加"1",就比x_1少一种可能。\\最终总共的选择方案就是(a_1+a_2+...+a_n)!种可能。

Eg:
X=180=22×32×5:22222×322×3×522×32×5,2+2+1=5举个例子:对X=180=2^2×3^2×5而言,有序列:2、2^2、2^2×3、2^2×3×5、2^2×3^2×5,长度为2+2+1=5。

3(b1,b2,b3)(1,0,0)(2,0,0)(2,1,0)(2,1,1)(2,2,1)"1""1"bibi+1<=ai反应到3元组(b_1,b_2,b_3)上来:它们的取值对应为(1,0,0)、(2,0,0)、(2,1,0)、(2,1,1)、(2,2,1),\\就是每一项在前一项的基础上加上了"1",这个"1"可以加在三个位置的b_i上,只要b_i+1<=a_i。

5a1+a2+a3=2+2+1=514...5对于序列的第一个数字,三个位置5个质因子共有a_1+a_2+a_3=2+2+1=5种取法,\\则第二个数字只能在其基础上增加1,共有4种取法...。因此共有5!种取法。

注意:
22(1,0,0)2,32!×2!=4由于在选择过程中,同一质因子在同一位置会重复被选择,例如:因子2有2个,(1,0,0)被计算选择了2次,\\因子3也被重复计算选择了两次,那么重复部分相同的不同序列就有2!×2!=4次,最后要除去重复的可能。

Eg:
22222×322×3×522×32×52232×2=4对序列:2、2^2、2^2×3、2^2×3×5、2^2×3^2×5,第一项有两个质因子2,故有2种选择,\\第三项和第四项的3可以调换位置,也有两种选择,那么该序列就被计算了2×2=4次。

a1!×a2!×a3!同理,对每一种不同的排列,都会存在重复的计算,次数为a_1!×a_2!×a_3!。

(a1+a2+a3)!a1!a2!a3!=30故最终总数为\frac{(a_1+a_2+a_3)!}{a_1!a_2!a_3!}=30种。

结论:

广,(i=1nai)!j=1naj!=(a1+a2+...+an)!a1!a2!...an!,i=1nai推广至一般情况,总方案数:\frac{(\sum_{i=1}^{n}a_i)!}{\prod_{j=1}^{n}a_j!}=\frac{(a_1+a_2+...+a_n)!}{a_1!a_2!...a_n!},同时最大长度\sum_{i=1}^{n}a_i。

解题步骤:

  1. 线X线性筛筛出X的所有最小质因子。
  2. 计算每个质因子的幂。
  3. 计算最终答案

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define ll long long
using namespace std;
const int N=(1<<20)+10;

int primes[N],cnt;  ///质数下标
int minp[N];  ///最小质因子
bool st[N];

void get_prime(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
        {
            minp[i]=i;
            primes[cnt++]=i;
        }
        for(int j=0; primes[j]*i<=n;j++)
        {
            int tmp=primes[j]*i;
            st[tmp]=true;
            minp[tmp]=primes[j];  ///tmp的最小质因子是primes[j]
            if(i%primes[j]==0) break;  ///prime[j]与当前筛的数相等了 退出
        }
    }
}

int main()
{
    get_prime(N);

    int index[30];  ///各质因子的指数,因为X<2^30,故质因子数量必小于30
    int x;
    while(~scanf("%d",&x))
    {
        memset(index,0,sizeof(index));
        int k=1;  ///指向第k位质因子
        int tot=0;  ///统计指数和
        while(x>1)
        {
            int p=minp[x];  ///取x的最小质因子
            while(x%p==0)
            {
                x/=p;
                index[k]++;
                tot++;
            }
            k++;  ///指向下一位质因子
        }

        ll ans=1;
        for(int i=1;i<=tot;i++) ans*=i;  ///分子:和的阶乘
        for(int i=1;i<=k;i++)  ///遍历每一位指数
            for(int j=1;j<=index[i];j++)  ///分母:阶乘的积
                ans/=j;

        printf("%d %lld\n",tot,ans);
    }

    return 0;
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!