【数论】AcWing 1295. X的因子链

https://www.acwing.com/problem/content/1297/

思路:要找符合条件的因子序列,使其长度最长,而且求出最长序列的个数。

显然各序列项之间的的倍数如果是最长了,那一定满足倍数是素数,否则这两个序列之间还可以插入一个新的项。

问题就转换为了,将一个数分解成素数相乘的的形式,求出乘数的个数(算术基本定理),以及有多少种排列方式(多重集的排列)

需要用到素数筛,并记录一个数的最小质因子。

剩下就很简单了。

但是这道题目的一个坑点在于求答案时会爆int,即使答案是一个很小的数,但由于是阶乘的结果作为中间过程,所以中间状态有可能会很大。答案要用long long 存储。

(自己的代码,这份代码最小质因子是现求的)

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int N = (2 << 20) + 10;

int primes[N],pl;
bool st[N];

int fac[N],ex[N],cnt;

void get_prime(int n)
{
    for(int i = 2;i <= n;i++)
    {
        if(!st[i])
        {
            primes[pl ++ ] = i;
        }
        for(int j = 0;primes[j] * i <= n;j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if(i % primes[j] == 0) break;
        }
    }
}

int main()
{
    get_prime(N);
    //for(int i = 0;i < 100;i ++) printf("%d\n",primes[i]);
    int x;
    while(scanf("%d", &x) != -1)
    {
        cnt = 0;
        for(int i = 0;x > 1;i ++ )
        {
            if(x % primes[i] == 0)
            {
                int f = primes[i];
                fac[cnt] = f;
                ex[cnt] = 0;
                do{
                    ex[cnt] ++ ;
                    x /= f;
                    //printf("%d: %d\t",fac[cnt],ex[cnt]);
                }while(x % f == 0);
                cnt ++ ;
            }
            //printf("%d: %d\t",fac[i],ex[i]);
            //x /= primes[i];
        }

        //printf("\n");

        long long int ans1 = 0, ans2;
        for(int i = 0;i < cnt;i++)
        {
            ans1 += ex[i];
        }

        ans2 = 1;
        for(int i = ans1;i > 1;i -- ) ans2 *= i;
        for(int i = 0;i < cnt;i++)//这个循环会爆int,切记
            for(int j = ex[i];j > 1; j --) ans2 /= j;

        printf("%d %d\n",ans1, ans2);
    }

    return 0;
}

 

posted @ 2020-10-15 17:14  褪色回音  阅读(89)  评论(0)    收藏  举报