c(n,m) = n!/(n-m)!m!
c++在處理大數除法的時候好像會出現問題,所以用除法有時候會因為精度不夠沒法得到正確答案.需要把除法變成乘法.
知識儲備:①逆元②快速冪
逆元:若a*x%m=1 我們稱x是a的逆元,x寫做a-1(相當於整除中的倒數),那假設我們要求a/b%m的值,當b特別大時我們無法得到正確答案,這時候對式子進行一些操作:
a / b % m = a / b * 1 % m = a / b * (b * b-1) % m --------------------- (b * b-1 % m = 1)
= a * b-1 % m
這時候只要求出b-1的值就可以求出a/b%m的值了.
怎樣求乙個數的逆元呢?
首先,要求乙個數的逆元,需要兩個元素,乙個是這個數,另乙個是模數.
a * a-1%m=1 若m是質數,根據費馬小定理a-1 = am-2 具體解釋可以在網上搜到.am-2就要用到快速冪了.
既然會求逆元了,怎麼求階乘的逆元呢?
①可以用線性演算法將1~n的所有逆元都求出來,設inv[i]是i的逆元.有性質:
inv[i] = (m- m/i) * inv[m%i] % m
然後將每個inv[i]乘起來就是i!的階乘的逆元
②可以從後往前倒推inv[1]
=1;for
(int i =
2;i <= n;i++
) inv[i]
=(m-m/i)
*inv[m % i]
%m;for
(int i =
1;i <= n;i++
) inv[i]
= inv[i-1]
*inv[i]
%m ;
若n!的逆元=k,那麼n-1!的逆元=kn
n! * k %m=1
n-1!=n!/n
n!/n * kn = 1
所以n-1!的逆元等於k*n
這種演算法首先求出i!,再求出n!的逆元.在倒推出i!的逆元
fac[1]
=1;for
(int i =
2;i<=n;i++
) fac[i]
=fac[i-1]
*i%m;
inv[n]
=quick_sort
(fac[n]
,m-2);
//根據費馬小定理
for(
int i = n-
1;i>=
1;i--
)inv[i]
= inv[i+1]
*(i+1)
%m;
組合數求模
大家都在中學階段學習了組合數的定義 這個表示的是從n個元素中選取m個元素的方案數。ps.組合數求模似乎只用在資訊學競賽和 acm競賽等計算機程式設計設計大賽中 求在現實中的運用 可以知道當n,m取得比較大的時候,組合數可能很大很大 天文數字?無法度量?例如 c 100,50 100891344545...
知識精華 組合數求模
大家都在中學階段學習了組合數的定義 這個表示的是從n個元素中選取m個元素的方案數。ps.組合數求模似乎只用在資訊學競賽和 acm競賽等計算機程式設計設計大賽中 求在現實中的運用 可以知道當n,m 取得比較大的時候,組合數可能很大很大 天文數字?無法度量?例如 c 100,50 10089134454...
組合數學 求組合數
對於求組合數,要根據所給資料範圍來選擇合適的演算法 這道題中所給的資料範圍適合用打表的方法直接暴力求解 先用4e6的複雜度預處理出所有的情況,再用1e4的複雜度完成詢問即可 include using namespace std const int n 2010 const int mod 1e9 ...