题目:
The binomial coefficient C(m, n) is defined as
C(m, n) = m!/ (m − n)! n!
Given four natural numbers p, q, r, and s, compute the the result of dividing C(p, q) by C(r, s).
Input
Input consists of a sequence of lines. Each line contains four non-negative integer numbers giving values for p, q, r, and s, respectively, separated by a single space. All the numbers will be smaller than 10,000 with p ≥ q and r ≥ s.
Output
For each line of input, print a single line containing a real number with 5 digits of precision in the frac- tion, giving the number as described above. You may assume the result is not greater than 100,000,000.
Sample Input
10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
Sample Output
0.12587
505606.46055
1.28223
0.48996
2.00000
3.99960
解题思路:原本打算开一个数组存放x的阶乘,但是这个数据看来,不对,结果证实会爆long long ,,long double,所以转换思路在分子分母的前提下,尽可能的去约分,总是选取最少的乘积次数,最后得到结果。
ac代码:
#include<bits/stdc++.h>
using namespace std;
typedef unsigned long long ull;
ull num[10050];
//错误写法,貌似会爆double
//且变化为int ll 之类的就会输出nan 可能是存在精度损失等问题
//int main()
//{
// num[0]=1;
// for(int i=1;i<=10000;i++)
// {
// num[i]=num[i-1]*i;
// }
// int p,q,r,s;
// while(scanf("%d%d%d%d",&p,&q,&r,&s)!=EOF)
// {
// double t=1.0*num[p]/(1.0*num[q])/(1.0*num[p-q]);
// double w=1.0*num[r]/(1.0*num[s])/(1.0*num[r-s]);
// printf("%.5lf\n",1.0*t/w);
// }
// return 0;
//}
//int main()
//{//找规律的 唯一分解定理 的取巧
// int p,q,r,s;
// while(scanf("%d%d%d%d",&p,&q,&r,&s)!=EOF)
// {
// q=min(q,p-q);
// s=min(s,r-s);
// double ans=1.0;
// for(int i=1;i<=q||i<=s;i++)
// {
// if(i<=q) ans = ans*(p-q+i)/i;
// if(i<=s) ans = ans* i/(r-s+i);
// }
// printf("%.5lf\n",ans);
// }
// return 0;
//}
int prime[10050];
int e[10050];
int cnt;
void db()
{
prime[0]=prime[1]=1;
for(int i=2;i<=sqrt(10050);i++)
if(!prime[i])
for(int j=i*2;j<=10050;j+=i)
prime[j]=1;
cnt=0;
for(int i=1;i<=10050;i++)
if(!prime[i])
prime[cnt++]=i;
}
void add_interger(int n,int d)
{
for(int i=0;i<cnt;i++)
{
while(n%prime[i]==0)
{
n/=prime[i];
e[i]+=d;
}
if(n==1)
break;
}
}
void updata(int n,int d)
{
for(int i=1;i<=n;i++)
add_interger(i,d);
}
int main()//唯一分解定理
{
db();
int p,q,r,s;
while(scanf("%d%d%d%d",&p,&q,&r,&s)!=EOF)
{
memset(e,0,sizeof(e));
updata(p,1);
updata(q,-1);
updata(p-q,-1);
updata(s,1);
updata(r-s,1);
updata(r,-1);
double ans=1.0;
for(int i=0;i<cnt;i++)
{
ans*=pow(prime[i],e[i]);
}
printf("%.5lf\n",ans);
}
return 0;
}