题目链接;http://acm.hdu.edu.cn/showproblem.php?pid=6114
求组合数的模版题。(代码也是在网上找的)
(Lucas定理:大整数求组合数取余定理)
Lucas定理用来求C(a,b)mod p的值,其中p为素数。
数学表达式为:
Lucas(a,b,q)=C(a%q,b%q)*Lucas(a/p,b/p,p);
Lucas(a,0,q)=0;
通过这个定理就可以很方便的把大数的组合转化成小数。但其中还是要求C(a%q,b%q)%p,所以这里引入逆元来求。
【定义】若整数a,b,p, 满足a·b≡1(mod p).则称a 为b 模p 的乘法逆元, 即a=b- 1mod p.其中, p 是模数。
应用到组合数中来就是:
a!/[b!(a-b)!] % p == a! [b!*(a-b)!]-1 %p
【逆元求法】:
应用费马小定理,ap-1=1 mod p ,即 a*ap-2=1 mod p
也就是说 ap-2就是a的逆元。
当然这里求出来的逆元是在取模p的逆元,对我们最终目标没有影响。这也是比较方便而且比较好的方法。
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL MOD=1000000007;
LL n,m;
LL quick_mod(LL a, LL b)
{
LL ans = 1;
a %= MOD;
while(b)
{
if(b & 1)
{
ans = ans * a % MOD;
b--;
}
b >>= 1;
a = a * a % MOD;
}
return ans;
}
LL C(LL n, LL m)
{
if(m > n) return 0;
LL ans = 1;
for(int i=1; i<=m; i++)
{
LL a = (n + i - m) % MOD;
LL b = i % MOD;
ans = ans * (a * quick_mod(b, MOD-2) % MOD) % MOD;
}
return ans;
}
LL Lucas(LL n, LL m)
{
if(m == 0) return 1;
return C(n % MOD, m % MOD) * Lucas(n / MOD, m / MOD) % MOD;
}
int main()
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%I64d%I64d", &n, &m);
if(m > n)
{
LL a;
a = m;
m = n;
n = a;
}
printf("%I64d\n", Lucas(n,m));
}
return 0;
}
//先预处理阶乘的逆元
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
const int maxn = 200005;
const LL MOD = 1000000007;
LL fac[maxn]={1},inv[maxn]={1};
//LL quick_mod(LL a, LL b)
//{
// LL ans = 1;
// a %= MOD;
// while(b){
// if(b & 1){
// ans = ans * a % MOD;
// b--;
// }
// b >>= 1;
// a = a * a % MOD;
// }
// return ans;
//}
//void init(){
// for(int i=1;i<maxn;i++){
// fac[i]=fac[i-1]*i%MOD;
// inv[i]=quick_mod(fac[i],MOD-2)%MOD;
// }
//}
LL extend_gcd(LL a, LL b, LL &x, LL &y) {
if(a == 0 && b == 0) return -1;
if(b == 0) {
x = 1;
y = 0;
return a;
}
LL d = extend_gcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
LL mod_reverse(LL a) {
LL x, y;
LL d = extend_gcd(a, MOD,x, y);
if(d == 1) return (x % MOD + MOD) % MOD;
else return -1;
}
void init(){
for(int i=1;i<maxn;i++){
fac[i]=fac[i-1]*i%MOD;
inv[i]=mod_reverse(fac[i]);
}
}
LL C(int m,int n){
if(m<n) return -1;
return fac[m]*inv[n]%MOD*inv[m-n]%MOD;
}
int main()
{
init();
int t;
LL n,m;
scanf("%d", &t);
while(t--)
{
scanf("%lld%lld", &n, &m);
if(m > n)
{
LL a;
a = m;
m = n;
n = a;
}
printf("%lld\n", C(n,m));
}
return 0;
}