算法笔记--卢卡斯定理

Lucas定理是用来(当n和m和p很大时)求 C(n,m) mod p,p为素数的值。

表达式:C(n,m)%p=C(n/p,m/p)*C(n%p,m%p)%p。(可以递归)

递归方程:(C(n%p, m%p)*Lucas(n/p, m/p))%p。(递归出口为m==0,return 1)

模板:

const int N=1e5+7;
int p;
ll fac[N];
void init()
{
    fac[0]=1;
    for(int i=1;i<=p;i++)fac[i]=fac[i-1]*i%p;
} 
ll q_pow(ll n,ll k)
{
    ll ans=1;
    while(k)
    {
        if(k&1)ans=ans*n%p;
        n=n*n%p;
        k>>=1;
    }
    return ans;
}
ll C(ll n,ll m)
{
    if(m>n)return 0;
    return fac[n]*q_pow(fac[m]*fac[n-m]%p,p-2)%p; 
} 
ll lucas(ll n,ll m)
{
    if(m==0)return 1;
    return (C(n%p,m%p)*lucas(n/p,m/p))%p;
}

例题1:451E - Devu and Flowers

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define pb push_back
#define pi acos(-1.0)
#define mem(a,b) memset(a,b,sizeof(a))

const int N=1e5+7;
int p;
ll fac[N];
ll f[25];
void init()
{
    fac[0]=1;
    for(int i=1;i<=p;i++)fac[i]=fac[i-1]*i%p;
} 
ll q_pow(ll n,ll k)
{
    ll ans=1;
    while(k)
    {
        if(k&1)ans=ans*n%p;
        n=n*n%p;
        k>>=1;
    }
    return ans;
}
ll C(ll n,ll m)
{
    if(n<m)return 0;
    if(n-m<m)m=n-m;
    ll s1=1,s2=1;
    for(int i=0;i<m;i++) 
    {
        s1=s1*(n-i)%p;
        s2=s2*(i+1)%p;
    }
    return s1*q_pow(s2,p-2)%p;
} 
ll lucas(ll n,ll m)
{
    if(m==0)return 1;
    return (C(n%p,m%p)*lucas(n/p,m/p))%p;
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    p=1e9+7;
    ll n,s;
    cin>>n>>s;
    for(int i=0;i<n;i++)cin>>f[i];
    ll ans=0;
    for(int i=0;i<(1<<n);i++)
    {
        ll sum=s,sign=1;
        for(int j=0;j<n;j++)
        {
            if(i&(1<<j))
            {
                sum-=f[j]+1;
                sign=-sign;
            }
        }
        if(sum<0)continue;
        ans+=sign*lucas(sum+n-1,n-1);
        ans%=p;
    }
    cout<<(ans+p)%p<<endl;
    return 0;
}
View Code

 

posted @ 2017-10-19 15:55  Wisdom+.+  阅读(335)  评论(0编辑  收藏  举报