算法笔记--卢卡斯定理
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; }
代码:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#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; }