(组合数求模=乘法逆元+快速幂) Problem Makes Problem
題目:
As I am fond of making easier problems, I discovered a problem. Actually, the problem is ‘how can you make n by adding k non-negative integers?’ I think a small example will make things clear. Suppose n=4 and k=3. There are 15 solutions. They are
2 0 2
2 1 1
2 2 0
3 0 1
3 1 0
4 0 0
As I have already told you that I use to make problems easier, so, you don’t have to find the actual result. You should report the result modulo 1000,000,007.
Input
Input starts with an integer T (≤ 25000), denoting the number of test cases.
Each case contains two integer n (0 ≤ n ≤ 106) and k (1 ≤ k ≤ 106).
Output
For each case, print the case number and the result modulo 1000000007.
Sample Input
4
4 3
3 5
1000 3
1000 5
Sample Output
Case 1: 15
Case 2: 35
Case 3: 501501
Case 4: 84793457
分析與解答
b * k ≡ 1 (mod p) 是什么意思?
就是(b*k)%p=1
a mod b是什么意思?
就是a%b
這兩個所有博客沒人說,但是我不清楚。。
先看看什么是乘法逆元
當我們要求(a / b) mod p的值,且 a 很大,無法直接求得a / b的值時,我們就要用到乘法逆元。
滿足 b * k ≡ 1 (mod p) 的 k 的值就是 b 關于 p 的乘法逆元。
我們可以通過求 b 關于 p 的乘法逆元 k,將 a 乘上 k 再模 p,即 (a * k) mod p。其結果與(a / b) mod p等價。
證:
因為 b * k ≡ 1 (mod p)
則有 b * k = p* x+1
得到 k = (p * x + 1) / b
將 k 代入(a * k) mod p
得到:
(a * (p * x + 1) / b) mod p
=((a * p * x) / b + a / b) mod p
=[((a * p * x) / b) mod p +(a / b)] mod p
=[(p * (a * x) / b) mod p +(a / b)] mod p
=(0 + (a / b)) mod p
= (a/b) mod p
1.用歐幾里得擴展求逆元
ax≡1(modp)
可以等價的轉化為ax?py=1 ,
檢查gcd(a,p)是否等于1 ,如果是的話
套用exgcd解方程
最后解出x即可
求出來的x有可能為負數,所以結果進行變化:
x = (x * (c/gcd) % b + b) % b; 即的a的乘法逆元的解x
2.用費馬小定理
費馬小定理:假如p是質數,且gcd(a,p)=1,那么 a^(p-1)≡1(mod p)
所以a*a^(p-2)≡1(mod p)
那a^(p-2)就是a的乘法逆元
可以利用快速冪計算
2.1那看看什么是快速冪
3^7 = 3 * 3^2 * 3^4
(7)10 = (111)2
———–4 2 1
3^15 = 3 * 3^2 * 3^4 * 3^8
(15)10 = (1111)2
———— 8 4 2 1
3^5 = 3 * 3^2 * 3^4
(5)10 = (101)2
———- 4 2 1
快速冪求x的y次方代碼:
int pow_1(int x,int y){//x的y次方 int ren=x;int ans=1;while(y){if(y&1) ans*=ren;//取當前最末位的y,如果是1就繼續(xù)乘ren ren*=ren;//下一位ren是當前ren的平方 1 2 4 8,這里8是x^4的平方,不是4的平方 y=y>>1;//y前進一位 }return ans; }3.用遞推法On求解
O(n)求1~n逆元表
有時會遇到這樣一種問題,
在模質數p下,求1~n逆元 n< p
這個問題有種很牛的算法,其基于以下的推導:
在求i的逆元時
p%i+[p/i]i=p
令a=p%i,b=[p/i],則有
a+bi=p
a+bi=0(mod p)
bi=-a(mod p)
i^-1=-b/a
也就是說i的逆元為:-[p/i]*(p%i)^-1
而p%i<i,那么可以從2遞推到n求逆元,在求i之前p%i一定已經求出
這樣就可以O(n)求出所有逆元了
(初始化 1^(-1)=1)
代碼如下
好了現(xiàn)在我們再看這題
代碼參考:
這題一個數拆成m個數相加,拆成的數可以是0,問有這m個數一共有幾種情況,看成是n個小球放到m個盒子里。
比如四個球放到三個盒子,盒子可以為空,怎么算的我實在不懂,先記住公式吧 方案數就是:C(n+m-1,m-1)
組合數公式:
約定f(a)代表a的階乘, C(m,n) = f(m)/(f(n)*f(m-n));
在本題就是C(n+m-1,m-1) = f(n+m-1)/(f(m-1)f(n));
本題代碼實現(xiàn):
我們打表用數組存一個數的階乘,
f(m)/(f(n) * f(m-n))%mod=(f(m)/f(n))%mod * (1/f(m-n))%mod
=f(m) * quick(f(m-1),mod-2) % mod quick(f(n),mod-2) % mod
a[n+k-1]quick(c,mod-2)%modquick(d,mod-2)%mod
現(xiàn)在做一下推廣
我們組合數求模的板子
/* mod=1e6+3 樣例輸入方式: 3 4 2 5 0 6 4 */ //這里直接求出C(M,N)%mod#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<cmath> using namespace std; const int INF=0x3f3f3f3f; typedef long long LL; const int mod=1e6+3; const int maxn=1e6+100; LL fac[maxn],inv[maxn]; LL Pow(LL a,LL b) { LL ans=1; while(b) { if(b&1) ans=(ans*a)%mod; a=(a*a)%mod; b>>=1; } return ans; } int main() { int cas=0; int n,a,b; fac[0]=1; //inv[0]=for(int i=1;i<=1000000;i++) { fac[i]=(fac[i-1]*i)%mod; //對階乘打表 // inv[i]=Pow(fac[i],mod-2); } scanf("%d",&n); while(n--) { scanf("%d%d",&a,&b); long long c=Pow(fac[b],mod-2); long long d=Pow(fac[a-b],mod-2); LL ans=fac[a]*c%mod*d%mod; printf("Case %d: %lld\n",++cas,ans); } return 0; }總結
以上是生活随笔為你收集整理的(组合数求模=乘法逆元+快速幂) Problem Makes Problem的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 世界手机号码格式_脑炎康复之旅——世界脑
- 下一篇: java图片资源存放_Java编程中图片