1. 程式人生 > >Wannafly挑戰賽25A——質因子分解

Wannafly挑戰賽25A——質因子分解

題目總結:哇,還真是質因子篩選!考試的時候想到了質因子個數相除,但不知道一個階乘該如何計算出一個因子的個數......

求一個大數n的階乘的所含因子p的個數,我們知道,

n!=1*2*3*4*......n

為求出p的個數,將上式表示為

n!=(p*2p*3p*4p*......*kp)*q,其中q就是其他不是因子p的倍數的乘積,比如10!=(2*(2*2)*(3*2)*......(5*2))*q,q是不含p的可以不管,k=n/p;

這樣,我們可以提出k個p出來,原式為

n!=p^k*k!*q,再將k!像上面的方法一樣分解,就可以得到p的個數

程式碼如下:

//階乘因子分解,找出n!中有多少個p
ll findnum(ll n,ll p)
{
    ll ans=0;//個數
    if(k==0)return 0;
    while(n)
    {
        ans+=n/p;//一次變換後的個數
        n/=p;//將k=n/p再迭代
    }
    return ans;
}

那麼,我們就可以將給定的p進行質因子分解,找出質因子和它們的個數,再用上述方法找到n!中p的每個質因子的個數,找到兩者相除的最小值就是答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;

typedef long long ll;
/*
     篩出p的最小質數和個數,再用快速演算法求出n!中含有多少個最小質數
     兩者個數相處就得到答案k
     快速求N!中有多少質數m的演算法就是迭代公式
*/

const ll maxn=10001;
int isprime[maxn];
int notprime[maxn];
ll n_num[maxn];//n的每個質因子個數
ll p_num[maxn];//p的每個質因子個數

int cnt;

//篩選質數
void eular()
{
    memset(isprime,0,sizeof(isprime));
    memset(notprime,0,sizeof(notprime));
    cnt=0;
    for(int i=2;i<maxn;i++)
    {
        if(!notprime[i])
        {
            isprime[++cnt]=i;
        }
        for(int j=1;j<=cnt&&i*isprime[j]<maxn;j++)
        {
            notprime[i*isprime[j]]=1;
            if(i%isprime[j]==0)
                break;
        }
    }
}

//階乘因子分解,找出n!中有多少個p
ll findnum(ll n,ll p)
{
    ll ans=0;
    while(n)
    {
        ans+=n/p;
        n/=p;
    }
    return ans;
}

int main()
{
    ll n,p;
    eular();
    int tot=1;
    while(scanf("%lld%lld",&n,&p)!=EOF)
    {
        memset(n_num,0,sizeof(n_num));
        memset(p_num,0,sizeof(p_num));
        while(p!=1)
        {
            //求p的每個質因子的個數
            while(p%isprime[tot]==0&&p)
            {
                p_num[tot]++;
                p/=isprime[tot];
            }
            tot++;
        }
        for(int i=1;i<=tot;i++)
        {
            n_num[i]=findnum(n,isprime[i]);
        }
        ll ans=2e18+5;
        for(int i=1;i<=cnt;i++)
        {
            if(p_num[i])
                ans=min(ans,n_num[i]/p_num[i]);//找一個最小的因子數之商
        }
        printf("%lld\n",ans);
    }
    return 0;
}