HDU3037Saving Beans 【组合数取模,即,LUCAS定理模板】
来源:互联网 发布:淘宝怎么选爆款 编辑:程序博客网 时间:2024/04/28 00:16
http://acm.hdu.edu.cn/showproblem.php?pid=3037
lucas定理的思想(待学):
http://blog.csdn.net/liangzhaoyang1/article/details/52132986?locationNum=7
http://blog.csdn.net/pi9nc/article/details/9615359
Now they turn to you for help, you should give them the answer. The result may be extremely huge; you should output the result modulo p, because squirrels can’t recognize large numbers.
Then followed T lines, each line contains three integers n, m, p, means that 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 a prime.
21 2 52 1 5
33HintHintFor sample 1, squirrels will put no more than 2 beans in one tree. Since trees are different, we can label them as 1, 2 … and so on. The 3 ways are: put no beans, put 1 bean in tree 1 and put 2 beans in tree 1. For sample 2, the 3 ways are: put no beans, put 1 bean in tree 1 and put 1 bean in tree 2.
题目相当于求n个数的和不超过m的方案数。
如果和恰好等于m,那么就等价于方程x1+x2+...+xn = m的解的个数,利用插板法可以得到方案数为:
(m+1)*(m+2)...(m+n-1) = C(m+n-1,n-1) = C(m+n-1,m)
现在就需要求不大于m的,相当于对i = 0,1...,m对C(n+i-1,i)求和,根据公式C(n,k) = C(n-1,k)+C(n-1,k-1)得
C(n-1,0)+C(n,1)+...+C(n+m-1,m)
= C(n,0)+C(n,1)+C(n+1,2)+...+C(n+m-1,m)
= C(n+m,m)
现在就是要求C(n+m,m) % p,其中p是素数。
然后利用Lucas定理的模板就可以轻松的求得C(n+m,m) % p的值
#include <iostream> #include <cstdio> //typedef __int64 lld; typedef long long lld; lld N,M,P; int Pow(lld a,lld n,lld p) { lld x = a; lld res = 1; while(n) { if(n & 1) { res = ((lld)res * (lld)x) % p; } n >>= 1; x = ((lld)x*(lld)x) % p; } return res; } int Cm(lld n,lld m,lld p) { lld a = 1,b = 1; if(m > n) return 0; //实现(a!/(a-b)!) * (b!)^(p-2)) mod p,由于n比较大,所以,此处不知道有什么好的优化 while(m) { a = (a * n) % p; b = (b * m) % p; m--; n--; } return ((lld)a * (lld)Pow(b,p-2,p))%p; } int Lucas(lld n,lld m,lld p) { if(m==0) return 1; return((lld)Cm(n%p,m%p,p)*(lld)Lucas(n/p,m/p,p))%p; } int main() { int t; //freopen("in.txt","r",stdin); scanf("%d",&t); while(t--) { scanf("%I64d%I64d%I64d",&N,&M,&P); printf("%d\n",Lucas(N+M,M,P)); } return 0; }
下面简单介绍一下Lucas定理:
Lucas定理是用来求 C(n,m) mod p的值,p是素数(从n取m组合,模上p)。描述为:Lucas(n,m,p)=C(n%p,m%p)* Lucas(n/p,m/p,p)Lucas(x,0,p)=1;
简单的理解就是:
以求解n! % p 为例,把n分段,每p个一段,每一段求得结果是一样的。但是需要单独处理每一段的末尾p,2p,...,把p提取出来,会发现剩下的数正好又是(n/p)! ,相当于划归了一个子问题,这样递归求解即可。
这个是单独处理n!的情况,当然C(n,m)就是n!/(m! *(n-m)!),每一个阶乘都用上面的方法处理的话,就是Lucas定理了
Lucas最大的数据处理能力是p在10^5左右。
而C(a,b) =a! / ( b! * (a-b)! ) mod p
其实就是求 a! /( (a-b)!) * ( b! ))^(p-2) mod p
(上面这一步变换是根据费马小定理:假如p是质数,且a,p互质,那么a的(p-1)次方除以p的余数恒为1,
那么a和a^(p-2)互为乘法逆元,则(b / a) = (b * a^(p-2) ) mod p)
用下面的Lucas定理程序实现就能得出结果,实现过程中要注意乘法时的强制转换
模板:
#include<bits/stdc++.h>using namespace std;typedef long long ll;ll n, m, p, f[10005];//f[n]=n!//组合数对p取模,p为素数且不能太大;复杂度为O(logp(n)*p)void init()//初始化{ f[0] =1; for(int i =1; i <= p; i++) f[i] = f[i-1]*i % p;}ll quickpow(ll a, ll b)//快速幂{ ll ans =1; while(b) { if(b &1) ans = ans * a % p; b>>=1; a = a*a % p; } return ans;}ll C(ll n, ll m){ if(m > n) return 0; return f[n]*q_pow(f[m]*f[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("%I64d%I64d%I64d", &n, &m, &p); init(); printf("%I64d\n", Lucas(n, m)); } return 0;}
- HDU3037Saving Beans 【组合数取模,即,LUCAS定理模板】
- HDU3037Saving Beans(lucas定理模板)
- hdu3037Saving Beans lucas定理
- HDU3037——Saving Beans(数论,组合数取模,lucas定理模板)
- hdu 3037 Saving Beans 【大组合数取模-Lucas定理+逆元取模】
- 大组合数取模 hdu 3037 Saving Beans lucas定理
- [ACM] hdu 3037 Saving Beans (Lucas定理,组合数取模)
- 【日常学习】【组合数取模Lucas定理】HDU3037 Saving Beans题解
- hdu 3037 Saving Beans (大组合数取模--Lucas定理)
- hdu-3037-Saving Beans(Lucas定理+大组合数取模)
- HDU 3037 Saving Beans 组合数取模 Lucas定理
- HDU - 3037 Saving Beans (数论,组合数取模,lucas定理)
- HDU_P3037 Saving Beans(Lucas定理+组合数取膜)
- HDU 3037 Saving Beans【Lucas定理】【模板题】【模板】【组合数取余】
- 【模板】组合数求余--lucas定理
- 【 Lucas定理 】 组合数取模
- Lucas定理---组合数取模
- lucas 定理,组合数取模
- 故障排查实战案例——某电器ERP系统日志暴增
- [Codeforces Round #195 DIV2E (CF336E)] Vasily the Bear and Painting Square
- 数据结构线性表(三)单链表的具体操作及整表创建
- 解决Genymotion出现Unable to load VirtualBox engine问题
- hdu 1702 ACboy needs your help again!(模板)
- HDU3037Saving Beans 【组合数取模,即,LUCAS定理模板】
- vector的用法
- C#发送邮件
- Android 里面的 Handler 究竟是如何保证线程安全的?
- 【洛谷P2756】 飞行员匹配方案 网络最大流
- 02-遇到多个构造器参数时要考虑用构建器
- 延迟变量
- java网络爬虫开发笔记
- wikioi1116 四色问题