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;
}
原文地址:https://www.cnblogs.com/scau20110726/p/2892324.html