1. 程式人生 > >Wannafly挑戰賽25 A 因子

Wannafly挑戰賽25 A 因子

時間限制:C/C++ 1秒,其他語言2秒
空間限制:C/C++ 262144K,其他語言524288K
64bit IO Format: %lld

題目描述 

令 X = n!, 給定一大於1的正整數p 求一個k使得 p ^k | X 並且 p ^(k + 1) 不是X的因子。

輸入描述:

兩個數n, p (1e18>= n>= 10000 >= p >= 2)

輸出描述:

一個數
表示k

示例1

輸入

複製

10000 12

輸出

複製

4996

題意:

找出一個k,使得X%p^k==0 && X%p^(k+1)!=0。

思路:

我們可以對一個數進行分解。一個數如果所有質因子的對應個數都小於等於另一個數的對應的個數,那麼這個數是另一個數的因子。否則不是。階乘的分解也很好推。

本題n的範圍是1e18,而p的範圍是10000,那麼我們就只需要考慮10000範圍內的質因子就行了。

程式碼:

#include<bits/stdc++.h>
using namespace std;
#define MAXN 10005
#define ll long long
#define inf 0x3f3f3f3f3f3f3f3f
#define mod 1000000007
ll n,p;
ll dp[MAXN],dis[MAXN];
int prime[MAXN];
bool is_prime[MAXN];
int sieve(int nn)
{
    int pn = 0;
    memset(is_prime,true,sizeof(is_prime));
    is_prime[0] = is_prime[1] = false;
    for(int i = 2; i <= nn; i++)
    {
        if(is_prime[i])
            prime[pn++] = i;
        for(int j=0; j<pn && prime[j]*i<=nn; j++)
        {
            is_prime[prime[j]*i]=false;
            if(i%prime[j]==0)   //¹Ø¼üµã
                break;
        }
    }
    return pn;
}

int main()
{
    scanf("%lld%lld",&n,&p);
    int cnt=sieve(10000);
    memset(dp,0,sizeof dp);
    for(int i=0;i<cnt && prime[i]<=n;i++)
    {
        ll num=prime[i];
        for(ll j=num;j<=n;j*=num)
        {
            if(j<0) break;
            dp[num]+=n/j;
        }
    }
    memset(dis,0,sizeof dis);
    ll minn=inf;
    for(int i=0;i<cnt && prime[i]<=p;i++)
    {
        ll num=prime[i];
        while(p && p%num==0)
        {
            dis[num]++;
            p/=num;
        }
        if(dis[num]==0) continue;
        minn=min(minn,dp[num]/dis[num]);
    }
    printf("%lld\n",minn);
    return 0;
}