C++Legendre定理及其例題講解—————方程

前言:

Legendre定理是一個你無法想象到的定理,而它的用處也是十分的大,現在親聽我慢慢講解。

Legendre定理:

設n爲一個正整數,那麼在n!的標準素因子分解式中,素數p的最高次項爲L_{p}(n!),則

                                                              L_{p}(n!)=\sum_{k\geq1} \left [ \frac{n}{p^k} \right ]

當模數不爲素數,且不方便使用CRT進行合併時,可以考慮對組合數分解質因數,由於組合數可以寫爲一個階乘除以兩個階乘的形式,可以對這三個階乘分別分解質因數,然後使用指數的減法,得到最後組合數的標準分解。

證明我就不在這裏細說了,反正這個定理可以讓我們快速求出p的指數。

下面是例題。

題目描述:

求方程x_{1}+x_2+......x_k=n的非負整數解的組數

n,k≤100,000,答案對20080814取模

輸入:

僅一行,包含兩個正整數n,k。

輸出:

一個整數,表示方程不同解的個數,這個數可能很大,你只需輸出mod 20080814 的結果。

樣例輸入:

1 1

樣例輸出:

1

思路分析:

利用隔板法,答案爲\LARGE C_{n+1}^{k-1}

由於20080814=2*13*772339(3個均爲質因數),故可以用CRT

也可以用Legendre定理分解階乘的質因數。

但是此題的輸入有坑,n,k需要特殊處理,詳見代碼。

代碼實現:

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
#define ll long long
ll n,m,p[200005],w[200005],k,ans=1;
bool v[200005];
ll olsf()//歐拉篩法求素數
{
    for(ll i=2;i<=n+1;i++)
    {
        if(!v[i])
        {
            k++;
            p[k]=i;
            v[i] = 1;
        }
        for(ll j=1;j<=k&&p[j]*i<=n+1;j++)
        {
            v[i*p[j]]=1;
            if(i%p[j]==0)
                break;
        }
    }
}
ll qkpow(ll x,ll y)//快速冪不解釋
{
    ll ans=1;
    while(y)
    {
        if(y&1)
            ans=(ans*x)%20080814;
        x=(x*x)%20080814;
        y/=2;
    }
    return ans%20080814;
}
int main()
{
    scanf("%lld%lld",&m,&n);
    n=n+m-1;
    m--;
    olsf();
    for(ll i=1;i<=k;i++)//求分子的分解
        for(ll j=p[i];j<=n;j*=p[i])
            w[i]+=n/j;
    for(ll i=1;i<=k;i++)//求分母的分解
        for(ll j=p[i];j<=m;j*=p[i])
            w[i]-=m/j;
    for(ll i=1;i<=k;i++)
        for(ll j=p[i];j<=n-m;j*=p[i])
            w[i]-=(n-m)/j;
    for(ll i=1;i<=k;i++)
        ans=(ans*qkpow(p[i],w[i]))%20080814;
    printf("%lld",ans);
}

鳴謝大佬的詳解。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章