https://codeforces.com/contest/893/problem/E
C(n,m)不越界但A(n,m)越界的解决方案
C(n,m) = A(n,m) / (n-m)!
这题要模1e9+7,但是只有加减乘能模,除法模不了。所以这个A(n,m)要存原值,原值也太大了,爆 long long
要是能不要除法,全是乘法就好了
法一:拆成多个质数相乘
先算A(n,m)里有多少个2 3 5 7,再减去(n-m)!中2 3 5 7的个数,最后把剩下的乘起来
long long C(int n, int m){
long long ret=1;
unordered_map<int,int> table;
for(int x=n;x>m;x--){
int tmpx=x;
for(int i=2;i<=tmpx;i++){
if(tmpx%i==0){
int tmpcnt=1;
tmpx=tmpx/i;
while(tmpx%i==0 && tmpx){
tmpcnt++;
tmpx/=i;
}
table[i]+=tmpcnt;
}
}
}
for(int x=n-m;x>=1;x--){
int tmpx=x;
for(int i=2;i<=tmpx;i++){
if(tmpx%i==0){
int tmpcnt=1;
tmpx=tmpx/i;
while(tmpx%i==0 && tmpx){
tmpcnt++;
tmpx/=i;
}
table[i]-=tmpcnt;
}
}
}
for(auto it=table.begin(); it!=table.end();it++){
int x=it->first;
int cnt=it->second;
ret=(ret*quickpower(cnt, x))%MOD;
}
return ret%MOD;
}
法二:除法转乘法
A / B ( m o d M ) ≡ A ∗ B M − 2 ( m o d M ) A/B \pmod{M} ≡ A*B^{M-2} \pmod {M} A/B(modM)≡A∗BM−2(modM)
费马小定理:若M是质数,且B、M互质,那么B^(M-1) mod M = 1
M自己就是质数,当然与B互质
A/B mod M
= A/B mod M * 1
= A/B mod M * B^(M-1) mod M
= A*B^(M-2) mod M
理论:逆元
逆元:bx ≡ 1 (mod M) ,称 x 是 b mod M 的逆元
(a / b) mod M = a * x mod M
(a / b) mod M
= (a / b) * 1 mod M
= (a / b) * (b * x) mod M
= a * x mod M
而 x(inv(b)) 的值:x ≡ b^{M-2} (mod M)
因为 b x ≡ 1 ( m o d M ) bx \equiv 1 \pmod M bx≡1(modM);
所以 b x ≡ b M − 1 ( m o d M ) bx \equiv b^{M-1} \pmod M bx≡bM−1(modM)(根据 费马小定理);
所以 x ≡ b M − 2 ( m o d M ) x \equiv b^{M-2} \pmod M x≡bM−2(modM)。
C(n,m)模板
C(n,m) mod M
= n! / m! / (n-m)! mod M
= n! * inv(m!) * inv((n-m)!) mod M
// f 阶乘,inv 逆元
long long f[MAXN],inv[MAXN];
long long quickpower(long long a, long long b){...}
void init()
{
f[0]=inv[0]=1;
for(long long i=1; i<maxn; i++)
{
f[i]=f[i-1]*i%MOD;
inv[i]=quickpower(f[i], MOD-2);
}
}
long long C(long long n, long long m)
{
return f[n] * inv[n-m]%MOD * inv[m]%MOD;
}
优化:从后往前求逆元可以使时间复杂度到O(n)
inv[i] = inv[i+1] * (i+1) % MOD
具体推导过程见代码
void init()
{
f[0]=inv[0]=1;
for (long long i = 1; i < maxn; i++)
{
f[i] = f[i - 1] * i % MOD;
}
inv[maxn-1] = quickpower(f[maxn-1], MOD - 2);
// 这里有个关系是 inv[i] * fac[i] == 1 % MOD
// 那么就有递推式 inv[i] * fac[i] * (i+1) == (i+1) % MOD
// 那么化简一下 inv[i] * fac[i+1] == (i+1) % MOD
// 两边同时除以 fac[i+1], 即为 inv[i] == (i+1) / fac[i+1] % MOD
// 右边可以进一步用逆元化简 inv[i] == (i+1) * inv[i+1] % MOD
for(int i = maxn-2; i>=0; i--){
inv[i] = inv[i+1] * (i+1) % MOD;
}
// inv[i] = quickpower(f[i], MOD - 2); 就不需要每次都quickpower计算了
}
二项式定理
C
(
n
,
0
)
+
C
(
n
,
1
)
+
C
(
n
,
2
)
+
.
.
.
+
C
(
n
,
n
)
=
2
n
C(n,0)+C(n,1)+C(n,2)+...+C(n,n) = 2^n
C(n,0)+C(n,1)+C(n,2)+...+C(n,n)=2n
(1+x)^n,给x赋值为1
C
(
n
,
1
)
+
C
(
n
,
3
)
+
C
(
n
,
5
)
+
.
.
.
=
2
n
−
1
C(n,1)+C(n,3)+C(n,5)+... = 2^{n-1}
C(n,1)+C(n,3)+C(n,5)+...=2n−1
C
(
n
,
0
)
+
C
(
n
,
2
)
+
C
(
n
,
4
)
+
.
.
.
=
2
n
−
1
C(n,0)+C(n,2)+C(n,4)+... = 2^{n-1}
C(n,0)+C(n,2)+C(n,4)+...=2n−1
(1+x)^n,给x赋值为-1
“memset”: 找不到标识符
#include<string.h>