Lucas定理&&hdu3037

来源:互联网 发布:买淘宝号一个多少钱 编辑:程序博客网 时间:2024/06/16 04:10

 

Lucas定理

Lucas定理主要应用于求C(n,m)%p  p是素数(从n取m组合,模上P)。

即:


所以:Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)


 

入门题:

Hdu3037 :

Saving Beans

 

Problem Description

…….

They want to know that howmany ways there are to save no more than m beans (they are the same) in n trees(different).

 

The result may be extremelyhuge; you should output the result modulo p

Input

The first line contains one integer T, means the number of cases.

Then followed T lines, each line contains three integers n, m, p, meansthat squirrels will save no more than m same beans in n different trees, 1<= n, m <= 1000000000, 1 < p < 100000 and p is guaranteed to be aprime.

 

Output

You should output the answermodulo p.

Sample Input

2

1 25

2 15

Sample Output

3

3

Hint

For sample 1, squirrels willput no more than 2 beans in one tree. Since trees are different, we can labelthem as 1, 2 … and so on.

The 3 ways are: put nobeans, put 1 bean in tree 1 and put 2 beans in tree 1. For sample 2, the 3 waysare:

 put no beans, put 1 bean in tree 1 and put 1bean in tree 2.

 

   题解:题目意思为求从n个不同的树上  得到不少于m个相同的豆子 ,问有几种解决方案。

首先,先解决排列组合的问题。即,将q个相同的小球,放进p个不同的盒子里(盒子可为空)的总方法数。

因为其盒子可以为空,不便计算,所以假设盒子里已经都有一个球,则球的总数为p+q,且盒子不得为空,那么用插板法,p+q个球中间有p+q-1个空,共要插入p-1个板,则为,C(p-1,p+q-1)

也可以这么理解:用插板法的话,其共有p-1个板子,将板子与小球混合,再选择p-1个位置,即C(p-1,p+q-1)

 

 

其次,不少于m个,即[0,m]个

所以,方法总数为:

ans=C(n-1,n-1)+ C(n-1,n)+ C(n-1,n+1)+…+ C(n-1,n+m-1)

由排列组合的性质:

C(m,n)=C(m,n-1)+C(m-1,n-1)

   (  证明:

对第m个讨论:

若选择了第m个,则在n-1中选m-1即C(n-1,m-1);

若未选择第m个,则在n-1中选m即C(n-1,m) 。      )

 

原式=C(0,n-1)+ C(1,n)+ C(2,n+1)+…+ C(m,n+m-1)

( C(m,n)= C(n-m,n))

= C(0,n)+ C(1,n)+ C(2,n+1)+…+ C(m,n+m-1)

( C(0,n-1)=C(0,n)= 1)

= C(1,n+1)+ C(2,n+1)+…+ C(m,n+m-1)

(C(m,n)=C(m,n-1)+C(m-1,n-1))

    = C(2,n+2)+ C(3,n+2)…+ C(m,n+m-1)

    …

    = C(m,n+m)

 

然后,因为题目中要求C(m,n)%p,而C(m,n)若很大,则处理起来会相当麻烦。

所以在此,还要介绍一下Lucas定理:

设p为素数,a,b为正整数,并且

a=akpk+ak-1pk-1+…+a1p+a0

b=bkpk+bk-1pk-1+…+b1p+b0

   ( 这里0=<ai, bi<=p-1都是整数,i=0,1,2…k.)

则:Cba≡ Cbkak *Cbk-1ak-1*…Cbk0ak0 (mod p) 

       

Lucas定理应用在编程中的就是:

 Lucas(n,m,p)=c(n%p,m%p)*Lucas(n/p,m/p,p)

 这就解决了C(m,n)太大求C(m,n)%p不便的问题了!

 

 最后再补充一个小知识——乘法逆元

因为 C(m,n)=n!/( m!*(n-m)!)

费马小定理欧拉函数求逆元):

若x是一个不能被质数p整除的整数,则xp-1-1必能被p整除。如果用同余式写法,就是xp-1≡1 mod p。

 

 

    另一种解释:  

假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒为1,那么a和a^(p-2)互为乘法逆元,则(b/ a) (b *a^(p-2) ) mod p

则C(m,n+m)= n! / ( m! * (n-m)!)

= n!* ( m! * (n-m)!)p-2

则C(m,n+m)%p = n!* ( m!* (n-m)!)p-2  %p

这里很明显,用一个快速幂就可以啦!

 

那么,题目分析到这里就结束了,接着代码就很容易了


#include <iostream>
#include <cstdio>
#include <cstring>
#define LL long long
#define maxn 150000
using namespace std;


LL n,m,p,fac[maxn];


void init()
{
    int i;
    fac[0]=1;
    for(i=1;i<=p;i++)
    fac[i]=fac[i-1]*i%p;
}
LL pow(LL a,LL b)
{
    LL temp=a%p,ans=1;
    while(b)
    {
        if(b%2) ans=ans*temp%p;
        temp=temp*temp%p;
        b>>=1;
    }
    return ans;
}


LL C(LL n,LL m)
{
    if(m>n) return 0;
    return fac[n]*pow(fac[m]*fac[n-m],p-2)%p;
}


LL Lucas(LL n,LL m)
{
    if(m==0) return 1;
    else  return (C(n%p,m%p)*Lucas(n/p,m/p))%p;
}


int main()
{
   int T;
   scanf("%d",&T);
   while(T--)
   {
       scanf("%lld%lld%lld",&n,&m,&p);
       init();
       printf("%lld\n",Lucas(n+m,n));
   }
  return 0;
}

 

 

0 0
原创粉丝点击