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;

}

 

你可能感兴趣的:(ide)