题意:给你四个数字p,q,r,s,计算C(p, q) / C(r, s)
思路:因为直接计算的话中间的结果会过大,所以不能直接计算我们可以使用唯一分解定理来把这个题目转换为阶乘这个样子就不会使中间的结果过大了。
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <string>
#include <vector>
#define MAXN 110000
#define MAXE 5
#define INF 100000000
#define MOD 10001
#define LL long long
#define pi 3.14159
using namespace std;
bool prime[MAXN];
LL P[MAXN];
LL mi[MAXN];
int cnt = 0;
void is_prime() {
memset(prime, true, sizeof(prime));
for (int i = 2; i <= 10010; ++i) {
if (prime[i]) {
P[cnt++] = i;
for (int j = 2 * i; j <= 10010; j += i) {
prime[j] = false;
}
}
}
}
LL power(LL a, LL b) {
LL ans = 1;
while (b) {
if (b & 1) {
ans *= a;
}
b >>= 1;
a = a * a;
}
return ans;
}
int main() {
//std::ios::sync_with_stdio(false);
is_prime();
LL p, q, r, s;
while (~scanf("%lld%lld%lld%lld", &p, &q, &r, &s)) {
memset(mi, 0, sizeof(mi));
double sum = 1;
for (LL i = q + 1; i <= p; ++i) {
LL num = i;
for (int j = 0; j < cnt; ++j) {
LL ans = 0;
if (num == 1) {
break;
}
while (num % P[j] == 0) {
ans++;
num /= P[j];
}
mi[j] += ans;
}
if (num > 1) {
sum *= num;
}
}
for (LL i = 2; i <= p - q; ++i) {
LL num = i;
for (int j = 0; j < cnt; ++j) {
LL ans = 0;
if (num == 1) {
break;
}
while (num % P[j] == 0) {
ans++;
num /= P[j];
}
mi[j] -= ans;
}
if (num > 1) {
sum /= num;
}
}
for (LL i = s + 1; i <= r; ++i) {
LL num = i;
for (int j = 0; j < cnt; ++j) {
LL ans = 0;
if (num == 1) {
break;
}
while (num % P[j] == 0) {
ans++;
num /= P[j];
}
mi[j] -= ans;
}
if (num > 1) {
sum /= num;
}
}
for (LL i = 2; i <= r - s; ++i) {
LL num = i;
for (int j = 0; j < cnt; ++j) {
LL ans = 0;
if (num == 1) {
break;
}
while (num % P[j] == 0) {
ans++;
num /= P[j];
}
mi[j] += ans;
}
if (num > 1) {
sum *= num;
}
}
for (int i = 0; i < cnt; ++i) {
if (mi[i] > 0) {
sum *= power(P[i], mi[i]);
} else {
sum /= power(P[i], -mi[i]);
}
}
printf("%.5f\n", sum);
}
return 0;
}
/*
10 5 14 9
93 45 84 59
145 95 143 92
995 487 996 488
2000 1000 1999 999
9998 4999 9996 4998
*/