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!(m−n)!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;
}