uva10375 Choose and Divide(唯一分解定理)
题意:
已知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位小数。
分析:
本题时间上基本上没有太大的限制,可以暴力求解C(m,n);
#include<cstdio> #include<cstring> #include<iostream> using namespace std; int P, Q, R, S; void solve() { int i, j, k; double ans = 1.0; if(P - Q < Q) Q = P - Q; if(R - S < S) S = R - S; for(i = 1; i <= S || i <= Q; i ++) { if(i <= Q) ans = ans * (P - Q + i) / i; if(i <= S) ans = ans / (R - S + i) * i; } printf("%.5lf ", ans); } int main() { while(scanf("%d%d%d%d", &P, &Q, &R, &S) ==4) solve(); return 0; }
但是我们会发现当数据再大一些,就已超出了计算机整数的表示范围,所以本题
我们使用唯一分解定理进行求解,通过将其分解为指数幂次相乘的形式即可
#include <cstdio> #include <cstring> #include <cmath> #include <iostream> using namespace std; const int MAXN=10000; int prime[MAXN+1]; int nprime; void getPrime(){ int m=sqrt(MAXN+0.5); memset(prime,0,sizeof(prime)); for(int i=2;i<=m;++i)if(!prime[i]) for(int j=i*i;j<=MAXN;j+=i) prime[j]=1; nprime=0; for(int i=2;i<=MAXN;++i){ if(!prime[i]) prime[nprime++]=i; } } int e[MAXN+1]; void add_integer(int n,int d){ for(int i=0;i<nprime;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(){ getPrime(); int p,q,r,s; while(scanf("%d%d%d%d",&p,&q,&r,&s)!=EOF){ 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); int maxn=max(p,r); double ans=1; for(int i=0;i<=maxn;i++){ ans*=pow(prime[i],e[i]); } printf("%.5lf ",ans); } return 0; }