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; }