定义
证明
代码实现
//lucas定理
//1.qpow,阶乘(init)
//2.lucas
//3.组合排列C(nm)
#include<bits/stdc++.h>
#define ll long long
using namespace std ;
const int mod = 110119 ;
ll jc[mod+1],nc[mod+1] ;
ll qpow(ll x,int k)
{
ll base = 1 ;
while(k)
{
if(k&1) base = base*x%mod ;
k>>=1 ;
x = x*x%mod ;
}
return base ;
}
void init()
{
jc[0] = 1 , nc[0] = 1 ;
for(int i = 1 ; i < mod ; i++)
{
jc[i] = jc[i-1]*i%mod ;
nc[i] = qpow(jc[i],mod-2) ;//费马小定理
}
}
ll compose(ll n,ll m)
{
if(n<0 || m<0 || n<m) return 0 ;
if(n==m) return 1 ;
return jc[n]*nc[n-m]%mod*nc[m]%mod ;
}
ll lucas(ll n,ll m)
{
if(n<0 || m<0 || n<m) return 0 ;
ll ans = 1 ;
while(n||m)
{
ans = ans*compose(n%mod,m%mod)%mod ;
n/=mod ;
m/=mod ;
}
return ans ;
}
int main()
{
init() ;
ll n,m ;
while(~scanf("%lld%lld",&n,&m))
{
printf("%lld\n",lucas(n,m)) ;
}
return 0 ;
}
例题
hdu5794
代码
#include<bits/stdc++.h>
#define ll long long
using namespace std ;
const int mod = 110119 ;
const int N = 105 ;
//思路:1.算出s1,s2,tot=s1+s2 ; C(s1,tot)即为总方案数
//2.减去障碍可以到达的方案数就ok
//3.对于当前点,f[i]=ans-障碍点可以到达的总方案数
//所以要对每个障碍数从小到大,算出其路径数,才可以
struct node{
ll x,y ;
bool operator < (node &b) const//小的排前边
{
if(x==b.x) return y<b.y ;
return x<b.x ;
}
}a[N];
ll f[N],jc[mod+1],ni[mod+1] ;
ll qpow(ll x,int k)
{
ll base = 1 ;
while(k)
{
if(k&1) base = base*x%mod ;
k >>= 1 ;
x = x*x%mod ;
}
return base ;
}
void init()
{
jc[0] = 1 , ni[0] = 1 ;
for(int i = 1 ; i < mod ; i++)
{
jc[i] = 1ll*jc[i-1]*i%mod ;
ni[i] = qpow(jc[i],mod-2) ;
}
}
int compus(int n,int m)
{
if(n<0 || m<0 || n<m) return 0 ;
return 1ll*jc[n]*ni[m]%mod*ni[n-m]%mod ;
}
int lucas(ll n,ll m)
{
//lucas定理 a = ∑ak*mod^k , b = ∑bk*mod^k
//C(a,b)=C(ak,bk)*C(ak-1,bk-1)*...*C(a1,b1)
if(n<m || n<0 ||m<0 ) return 0 ;
int ans = 1 ;
while(n||m)
{
ans = 1ll*ans*compus(n%mod,m%mod)%mod ;
n/=mod ;
m/=mod ;
}
return ans ;
}
int main()
{
ll n,m ;
int t,kase=0 ;
init() ;
while(~scanf("%lld%lld%d",&n,&m,&t))
{
for(int i = 1 ; i <= t ; i++) scanf("%lld%lld",&a[i].x,&a[i].y) ;
a[++t]= (node){n,m} ;
sort(a+1,a+t+1) ;
memset(f,0,sizeof(f)) ;
for(int i = 1 ; i <= t ; i++)
{
ll s = a[i].x+a[i].y-2 ;
if(s%3) continue ; //总步数s%3=0才可以走到该点
s/=3 ;
//ll s1 = a[i].x-1-s ;//向x方向走的步数
ll s1 = (2ll*a[i].x-a[i].y-1)/3 ;
f[i] = lucas(s,s1) ;//C(s1,s)
//printf("x=%d y=%d s=%d s1=%d f[%d]=%lld \n",a[i].x,a[i].y,s,s1,i,f[i]) ;
for(int j = 1 ; j < i ; j++)//正确算出i点的路径数
{
if(a[j].x>a[i].x || a[j].y>a[i].y) continue ;
ll ss = a[i].x-a[j].x+a[i].y-a[j].y ;
if(ss%3) continue ;
ss/=3 ;//总步数
//ll s2 = a[i].x-a[j].x-ss ;//向x方向走的步数
ll s2 = (2ll*(a[i].x-a[j].x)-(a[i].y-a[j].y))/3 ;
//printf("x=%d y=%d ss=%d s2=%d lucas=%lld \n",a[j].x,a[j].y,ss,s2,lucas(ss,s2)) ;
f[i] = (f[i]-1ll*f[j]*lucas(ss,s2)%mod+mod)%mod ;
}
}
printf("Case #%d: %d\n",++kase,f[t]) ;
}
return 0 ;
}
参考:(9条消息) 卢卡斯定理(十分钟带你看懂)_Combatting 的博客-CSDN博客_卢卡斯定理(9条消息) hdu5794_weixin_34071713的博客-CSDN博客