UVa10375(唯一分解定理)
阿新 • • 發佈:2019-01-31
例題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)。輸出保證不超過108,保留5位小數。
【分析】
本題正是唯一分解定理的用武之地。組合數C(m,n)的性質將在10.2.1節中介紹,本題只 需要用到它的定義。
首先,求出10000以內的所有素數primes,然後用陣列e表示當前結果的唯一分解式中各 個素數的指數。例如,e={1,0,2,0,0,0,…}表示2^1*5^2=50。
唯一分解:任何一個大於1的數n,可分解為若干素數相乘的形式。
以上摘自劉汝佳前輩紫書。
【程式碼】:
#include<bits/stdc++.h> using namespace std; int pri[15100],top,t[15100]; bool vis[15100]; void prime() { memset(vis,1,sizeof(vis)); top=0; for(int i=2;i<11000;i++) if(vis[i]) { pri[top++]=i; for(int j=i+i;j<11000;j+=i)vis[j]=0; } } void get(int n,int flag)//將n的階乘唯一分解,存入t[] { for(int i=n;i>1;i--) { int k=i; for(int j=0;j<top&&k>1;j++) while(k>1&&k%pri[j]==0){ t[j]+=flag;k/=pri[j]; } } } int main() { prime(); int p,q,r,s; while(cin>>p>>q>>r>>s) { memset(t,0,sizeof(t)); get(p,1); get(s,1); get(r-s,1); get(q,-1); get(p-q,-1); get(r,-1); /*for(int i=0;i<10;i++) printf("%d ",t[i]); puts("");*/ double ans=1; for(int i=0;i<top;i++) { ans*=pow(pri[i],t[i]); } printf("%.5lf\n",ans); } }
另外我之前用了對數優化的方式,沒過。不知道是不是精度損失的問題,附程式碼,還請大佬指教:
#include<bits/stdc++.h> using namespace std; double fac[10109]; int main() { fac[0]=log(1); for(int i=1;i<10101;i++) fac[i]=log(1.0*i)+fac[i-1]; int p,q,r,s; while(cin>>p>>q>>r>>s) { double y=fac[p]+fac[s]+fac[r-s]-fac[q]-fac[p-q]-fac[r]; printf("%.5lf\n",exp(y)); } }