uva 10375 Choose and divide
数学题:(组合数学,分解质因子)
题意就是C(m,n)/C(s,t),凡是组合数就提醒我们要注意数据范围,一般处理组合数学问题的策略就是能约分的先约分,能化简的先化简,能除的先除,不要全部乘起来再除掉
1.转化公式
C(m,n) = [ m*(m-1)*(m-2)...(m-n+1) ] / [ n! ]
2.两者相除
C(p,q)/C(r,s) = [ p*(p-1)...(p-q+1) * s! ] / [ r*(r-1)....(r-s+1)*q! ]
但是不能全部乘起来再除(爆),也不能一边乘一边除(精度),把每个数字分解质因子,分子中分解出来的质因子,个数增加,分母分解出来的质因子,个数减少
最后查看所有的质因子,个数为正的要乘,个数为负的要除,要一边乘一边除否则又会爆
代码写得不好,可以优化一下提高时间的,但是没心机写了就不优化了,跑了0.980s
#include <cstdio> #include <cstring> #define MAX 10000 int c[MAX+100]; //质因子 //将i分解为质因子并使质因子数增加 void div(int n ,int f) { for(int i=2; n>1; i++) if(!(n%i)) //能分解因子 { while(n>1 & !(n%i)) { c[i]+=f; n/=i; } } } void solve(int p,int q,int s,int t) { //分子: p……p-q+1 * t! //分母: s……s-t+1 * m! double a,b,ans; memset(c,0,sizeof(c)); for(int i=p; i>=p-q+1; i--) div(i,1); for(int i=t; i>=1; i--) div(i,1); //将i分解为质因子并使质因子数增加 for(int i=s; i>=s-t+1; i--) div(i,-1); for(int i=q; i>=1; i--) div(i,-1); //将i分解质因子并使质因子数减少 ans=a=b=1; for(int i=1; i<=MAX; i++) //扫描所有质因子 if(c[i]>0) for(int k=1; k<=c[i]; k++) ans*=i; else if(c[i]<0) for(int k=c[i]; k<0; k++) ans/=i; printf("%.5f\n",ans); } int main() { int p,q,s,t; while(scanf("%d%d%d%d",&p,&q,&s,&t)!=EOF) { solve(p,q,s,t); } return 0; }