Uva10375 Choose and divide(数论、唯一分解定理、快速幂)

Uva10375 Choose and divide(数论、唯一分解定理、快速幂)

链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1316


题目

Time Limit:3000MS Memory Limit:0KB
Description
The binomial coefficient C(m, n) is defined as C(m, n) = m!(mn)!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 fraction, 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


题意

给你两对数,让你用题目所给组合数公式去求C(p, q)除C(r, s)的结果


分析

如果暴力算肯定超时,我们可以思考一下怎样简化相除的过程:通过唯一分界定理,记录每个因子的数量,可以认为是进行上下约分操作,最后只需要对各个因子进行相除即可。


源码

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
#include<vector>
#include<algorithm>
#include<string>
#include<sstream>
#include<cmath>
#include<set>
#include<map>
#include<vector>
#include<stack>
#include<utility>
#include<sstream>
#define mem0(x) memset(x,0,sizeof x)
#define mem1(x) memset(x,-1,sizeof x)
#define dbug cout<<"here"<<endl;
//#define LOCAL

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int MAXN = 1e6+10;
const int MOD = 1000000007;

ull p,q,r,s;
ll cnt[10010];

ull quickPow(ull a, ull b){
    ull ans = 1;
    while(b){
        if(b & 1){
            ans = ans*a;
        }
        b = b >> 1;
        a = a*a;
    }
    return ans;
}

void division(ull a, int type){
    int up = sqrt(a+1);
    for(int i = 2; i < up; ++i){
        if(a%i == 0){
            while(a%i == 0){
                a /= i;
                cnt[i] += type;
            }
        }
        if(a == 1)
            break;
    }
    if(a>1)
        cnt[a] += type;
}

void addElement(ull n){
    for(int i = 1; i <= n; ++i){
        division(i, 1);
    }
}

void incElement(ull n){
    for(int i = 1; i <= n; ++i){
        division(i, -1);
    }
}

void solve(){
    double ans = 1;
    for(int i = 1; i <= 10000; ++i){
        if(cnt[i]>0){
            ans *= quickPow(i, cnt[i]);
        }
        else if (cnt[i]<0){
            ans /= quickPow(i, abs(cnt[i]));
        }
    }
    printf("%.5lf\n",ans);
}

int main(){
    #ifdef LOCAL
        freopen("C:\\Users\\asus-z\\Desktop\\input.txt","r",stdin);
        freopen("C:\\Users\\asus-z\\Desktop\\output.txt","w",stdout);
    #endif
    while(cin >> p >> q >> r >> s){
        mem0(cnt);
        addElement(p);
        addElement(r-s);
        addElement(s);
        incElement(r);
        incElement(p-q);
        incElement(q);
        solve();
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值