【算法随记】C(n,m)不越界但A(n,m)越界;C(n,1)+C(n,3)+C(n,5)...等二项式定理;“memset”: 找不到标识符

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)ABM2(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 bx1(modM)
所以 b x ≡ b M − 1 ( m o d M ) bx \equiv b^{M-1} \pmod M bxbM1(modM)(根据 费马小定理);
所以 x ≡ b M − 2 ( m o d M ) x \equiv b^{M-2} \pmod M xbM2(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)+...=2n1
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)+...=2n1
(1+x)^n,给x赋值为-1

“memset”: 找不到标识符

#include<string.h>
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值