选择与除法
已知C(m,n) =m!/(n!(m-n)!),输入整数p, q,1,s ( p=q , r2s , p.q ,7,s≤10000 ) ,计算C(p,q)/C(r,s)。输出保证不超过108,保留5位小数。
【分析】
1.预处理素数表,分解每一个1~100002.
2.将乘除法变成素数指数的加减法(唯一分解定理)
C(p,q)/C(r,s)=p!s!(r−s)!/r!q!(p-q)!
值得注意的是可以通过阶乘质因子分解公式来提高我们的效率。
阶乘质因子分解公式:N的阶乘的质因子m的指数:X = [N/m] +[N/m^2] +[N/m^3] +…+[N/m^(logm N)(注意,每个[ ]都取整数部分。直到N/m^(logm N)结束
比如当m=2时,
X = [N/2] +[N/2^2] +[N/2^3] +…,[N/2]表示不大于N的数中2的倍数贡献一个2,[N/22]表示不大于N的数中2^2的倍数贡献两个2。代码如下:
ret = 0;
while(N)
{
ret += N / 2;
N /= 2;
}
这里使用的是Eratosthenes筛法求素数。(嗯,才10000,挺快的)
#include <iostream>
#include <vector>
#include <math.h>
#include <iomanip>
using namespace std;
const int max_su = 10010;
vector<int> is_shusu(max_su + 1, 1);
vector<int> shusu;
vector< vector<int> > zhi_index(max_su, vector<int>(6));
int Zhi(int jiecheng, int su)
{
int res = 0;
while (jiecheng)
{
res += jiecheng / su;
jiecheng /= su;
}
return res;
}
int main()
{
for (int i = 2; i < max_su; i++)
{
if (is_shusu[i])
{
shusu.push_back(i);
for (int j = i * i; j < max_su; j += i)
{
is_shusu[j] = false;
}
}
}
int p, q, r, s;
cin >> p >> q >> r >> s;
zhi_index[0][0] = p, zhi_index[0][1] = s, zhi_index[0][2] = r - s;
zhi_index[0][3] = r, zhi_index[0][4] = q, zhi_index[0][5] = p - q;
//
for (int i = 0; i < 6; i++)
{
for (int j = 0; shusu[j] <= zhi_index[0][i]; j++)
{
zhi_index[shusu[j]][i] = Zhi(zhi_index[0][i], shusu[j]);
}
}
for (int j = 0; j < shusu.size(); j++)
{
zhi_index[j][0] = zhi_index[shusu[j]][0] + zhi_index[shusu[j]][1] + zhi_index[shusu[j]][2]
- zhi_index[shusu[j]][3] - zhi_index[shusu[j]][4] - zhi_index[shusu[j]][5];
}
double rse = 1.0;
for (int i = 0; i < shusu.size(); i++)
{
rse *= pow(shusu[i], zhi_index[i][0]);
}
cout.setf(ios::fixed);
cout << setprecision(5)<< rse;
//10 5 14 9
return 0;
}