《算法竞赛经典入门》
例题10-3 选择与除法(Choose and Divide,UVa10375)
题目:
已知 C(m,n) = m!/(n!(m-n)!), 输入整数p,q,r,s,(p >= q ,
r>=s,p,q,r,s<=10000),计算C(p,q)/C(r,s)。输出保证不超过10的8次方,保留5位小数。
分析:
看了书,这道题是唯一分解定理(也就是任意的数总能分解为若干个素数的积)的应用。可以在草纸上把结果的表达式写出来,一目了然。思路是构造一个1-10000内素数的数组,另外索引对应的构造一个数组代表每个素数次数。
代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=10000+5;
int e[maxn],SelectPrime[maxn];
vector<int> prime;
//利用Eratosthenes筛法排除
void Prime(int a[],int m)
{
for(int i=2;i<=sqrt(m)+1;i++) if(!a[i])
for(int j=i*i;j<=m;j += i) a[j] = 1;
}
void add_integer(int n,int d)
{
for(unsigned int i=0;i<prime.size();i++)
{
while(n%prime[i]==0)
{
n/=prime[i];
e[i] += d;
}
if(n==1) break;
}
}
void add_factorial(int n,int d)
{
for(int i=1;i <= n;i++)
add_integer(i,d);
}
int main()
{
int p,q,r,s;
while(cin>>p>>q>>r>>s)
{
memset(SelectPrime,0,sizeof(SelectPrime));
Prime(SelectPrime,maxn);
//这个循环产生了1-10000的素数
for(int i=2;i<=maxn;i++) if(!SelectPrime[i])
prime.push_back(i);
memset(e,0,sizeof(e));
//这些是为了分解
add_factorial(p,1);
add_factorial(q,-1);
add_factorial(p-q,-1);
add_factorial(r,-1);
add_factorial(s,1);
add_factorial(r-s,1);
double ans=1;
for(unsigned int i=0;i<prime.size();i++)
ans *= pow(prime[i],e[i]);
printf("%.5lf\n",ans);
}
return 0;
}