Lucas 应用

主要用来当求C(n,m)%p;  这里的n,m很大,不能用数组表示,而p可以用数组表示时。 

 

hdu:  3037 Saving Beans

题意:

模型是有m + 1个球(0,1,2.....m),放到n个盒子里面,问有多少种方法。 典型的球同,盒不同,不允许空箱 C(n + m + 1 - 1,m + 1 - 1);

思路:
因为这里n,m太大,无法直接求,所以利用Lucas(n,m,p) = C(n%p,m%p)*Lucas(n/p,m/p,p)来求。

 

View Code
//#pragma comment(linker,"/STACK:327680000,327680000")
#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <functional>
#include <numeric>
#include <sstream>
#include <stack>
#include <map>
#include <queue>

#define CL(arr, val)    memset(arr, val, sizeof(arr))

#define lc l,m,rt<<1
#define rc m + 1,r,rt<<1|1

#define ll __int64
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   (l + r) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)        (1 << (x))
#define iabs(x)     (x) < 0 ? -(x) : (x)
#define OUT(x)  printf("%I64d\n", x)
#define lowbit(x)   (x)&(-x)
#define Read()  freopen("din.txt", "r", stdin)
#define Write() freopen("dout.txt", "w", stdout);


#define M 26
#define N 100007


using namespace std;


const int inf = 0x1F1F1F1F;
const int mod = 1000000007;
const int X = 1000000005;

ll fac[N];
ll n,m,p;

void init()
{
    fac[0] = 1;
    for (int i = 1; i <= p; ++i)
    {
        fac[i] = fac[i - 1]*i%p;
    }
}
ll modexp(ll a,ll b, ll c)
{
    ll rs = 1;
    ll tmp = a%p; //注意这里先要模p
    while (b)
    {
        if (b&1) rs = rs*tmp%c;
        tmp = tmp*tmp%p;
        b >>= 1;
    }
    return rs;
}
ll C(ll x,ll y)
{
    if (y > x) return 0;//注意这里出现访问越界的处理
    ll ans = fac[x]*modexp(fac[y],p - 2,p)%p;
    ans = ans*modexp(fac[x - y],p - 2,p)%p;
    return ans;
}
ll Lucas(ll n,ll m,ll p)
{
    if (m == 0) return 1;
    return (C(n%p,m%p)*Lucas(n/p,m/p,p))%p;
}
int main()
{
    int T;
    scanf("%d",&T);
    while (T--)
    {
        scanf("%I64d%I64d%I64d",&n,&m,&p);
        init();
        printf("%I64d\n",Lucas(n + m,m,p));
    }
    return 0;
}

 

 Lucas 的推广

HDU  4349 Xiao Ming's Hope

题意:

给定n,求C(n,0) ,C(n,1) ...... C(n,n)中存在多少奇数。

思路:

求C(n,m)%2  是否为1即可。看到这个式子我们应该想到Lacus定理,然后想到他的证明,n用2进制表示,然后把每一位取出来计算 假设n = 10010011  m满足什么条件C(n,m)才是奇数呢?很简单,当n的i位为1时,m对应0,1都是(C(1,0) = C(1,1) )1,当n的i位为0时,如果我们取1 C(0,1) = 0那么最终 C(n,m)为偶数,  所以我们只能取0,C(0,0)为1,不影响奇性

 所以我们只要枚举n所对应的的位为1的取0,1即可。

int main()
{
    int n;
    while (~scanf("%d",&n))
    {
        int sum = 0;
        while (n)
        {
            if (n&1) sum++;
            n >>= 1;
        }
        cout<<(1<<sum)<<endl;
    }
    return 0;
}

 

 

posted @ 2013-04-30 11:47  E_star  阅读(279)  评论(0编辑  收藏  举报