例题10-3 选择与除法(Choose and Divide,UVa10375)

《算法竞赛经典入门》

例题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;
}

猜你喜欢

转载自blog.csdn.net/ishandsomedog/article/details/78884033