题目大意
给定n,m (n,m≤232) 求 Cnn+m
分析
裸的求组合数的题
原公式是:
Cmn=AmnAmm=n!m!(n−m)!=n∗(n−1)...∗(n−m+1)m!=n∗(n−1)∗...∗(m+1)(n−m)!
不能直接阶乘后做除法会溢出
百度后总结一下求组合数的几种方法(组合数combinatorial number)
1.递推法
可以通过公式:
Cmn=Cm−1n+Cm−1n−1
递推求出,但是对于n太大的情况就不适用了
2.取对数法
为了避免直接计算n的阶乘,对公式两边取对数,于是得到:
ln(Cmn)=∑ni=1ln(i)−∑mi=1ln(i)−∑n−mi=1ln(i)
通过取对数将连乘转化成了连加
化简一下得到: ln(Cmn)=∑ni=m+1ln(i)−∑n−mi=1ln(i)
之后 Cmn=expln(Cmn)
3.拆分阶乘
这个方法其实把阶乘拆分成若干分式后用double来做
需要注意的是精度的处理问题
直接看题解了
知道做法后这道题还是挺水的
代码
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdlib>
#include<queue>
using namespace std;
#define uint unsigned int
uint Comb(uint n,uint m)//¼ÆËã×éºÏÊý
{
uint a=n+m;
uint b=min(n,m);
double ans=1.0;
while(b>0)
{
ans=ans*((double)(a--)/(double)(b--));
}
ans+=0.5;
return (uint)ans;
}
int main()
{
uint n,m;
while(scanf("%u%u",&n,&m)!=EOF)
{
if(n==0 && m==0)break;
cout<<Comb(n,m)<<endl;
}
}