zoukankan      html  css  js  c++  java
  • 数学专题

    线性筛素数

    int pj[N], cnt, vis[N];
    
    void get_primes(int n) {
    	for(int i = 2; i <= n; i ++) {
    		if(!vis[i])	   pj[++ cnt] = i;
    		for(int j = 1; pj[j] * i <= n; j ++) {
    			vis[pj[j] * i] = true;
    			if( i % pj[j] == 0)    break; 
    		} 
    	}
    } 
    

    唯一分解定理:(x = prod p_{i} ^ {a_{i}})

    约数个数定理: (prod (a_i + 1))

    约数个数和定理: (prodsum_{i = 0}^{a_i}p_j^i)

    最大公约数: (gcd(a,b) = gcd(b, a mod b))

    线性筛phi

    (φ(n) = N prod (1 - frac{1}{p_i}))

    void get_primes(int n) {
        phi[1] = 1;
        for(int i = 2; i <= n; i ++) {
    	if(!vis[i])	   primes[++ cnt] = i, phi[i] = i - 1;
    	for(int j = 1; primes[j] * i <= n; j ++) {
    	    vis[primes[j] * i] = true;
    	    if( i % primes[j] == 0) {
    	    phi[i * primes[j]] = phi[i] * primes[j];
    	    break; 
    	}
    	phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    } 
    

    欧拉定理:

    [a ^{φ(n)} equiv 1 quad(mod n) ]

    其中,((a,n)=1)

    证明:
    引入一个概念: 缩系

    [R_n = {c_1, c_2, c_3, .... .c_{φ(n)} }, quad (c_i, n) = 1 ]

    同时乘上a, 也是mod n 的一个缩系,因为乘上a之后,两两互不同余,并且仍然与n互质。

    [prod_{i = 1}^{φ(n)}c_i equiv prod_{i = 1}^{φ(n)}ac_i ]

    [prod_{i = 1}^{φ(n)}c_i equiv a^φ(n) prod_{i = 1}^{φ(n)}c_i ]

    两边约去公因数,得到欧拉定理。

    如果 (n)为素数, 可以得到 费马小定理

    [a^{p - 1} equiv 1quad(mod p) ]

    由此,可以得到

    [a * a^{p - 2} equiv 1quad(mod p) ]

    所以,如果模数是素数,那么a的逆元就是(a^{p-2}),可以用快速幂求。

    扩展欧几里得exgcd:

    exgcd求解方程

    [ax +b y = gcd(a,b) ]

    由于

    [gcd(a,b) = gcd(b,a mod b) ]

    所以,我们可以写成和上面的方程一样的形式:

    [b x + (a mod b)y = gcd(a,b) ]

    进一步化简

    [bx + (a - lfloor frac{a}{b} floor b)y = gcd(a, b) ]

    [ay + b(x - lfloor frac{a}{b} floor y) = gcd(a, b) ]

    所以

    [x' = y, y' = x - lfloor frac{a}{b} floor y ]

    通解

    [x_k = x_0 + frac{kb}{gcd(a, b)}, y_k = x_0 - frac{ka}{gcd(a, b)} ]

    代码:

    void exgcd(int& x, int& y, int a, int b) {
    	if(!b) {
    		x = 1, y = 0;
    		return; 
    	} 
    	exgcd(y, x, b, a % b);
    	y -= (a / b) * x;
    }
    
    

    中国剩余定理

    给定 (2n) 个整数(a_1,a_2,…,a_n)(m_1,m_2,…,m_n,)求一个最小的非负整数 (x),满足(∀i∈[1,n],x≡m_i(mod a_i))并且模数两两互质。
    首先,设

    [M = prod_{i = 1}{n} b_i ]

    [m_i = frac{M}{bi} ]

    求解

    [m_i * m_i^{-1} equiv 1 ]

    [x = sum_{i = 1}^{n}a_i * m_i * m_i^{-1} ]

    for(int i = 1; i <= n; i ++) {
    	scanf("%lld%lld", &mo[i], &re[i]);
    	M *= mo[i];
    }
    for(int i = 1; i <= n; i ++) {
    	m[i] = M / mo[i];
    	LL tmp;
    	exgcd(inv[i], tmp, m[i], mo[i]);
    }
    LL ans = 0;
    for(int i = 1; i <= n; i ++) {
    	ans += (re[i] * m[i] * inv[i]);
    }
    printf("%lld
    ", (ans % M + M) % M); 
    

    扩展中国剩余定理exCRT

    首先考虑两个方程,
    (x ≡ a_1(mod m_1))

    (x ≡ a_2(mod m_2))

    进一步,写成等式:
    (x = k_1 * m_1 + a_1)
    (x = k_2 *m_2 + a_2)
    两式相等,得到:
    (k_1 *m_1-k_2*m_2 = a_1-a_2)
    只有(k_1)(k_2)是未知数,可以用exgcd进行求解。
    (d = gcd(m_1, m_2)),那么,(k_1)的通解为(k_t = k_1 + t * frac{m_2}{gcd(m_1,m_2)})
    所以(x = k_t * m_1 +a_1 = t * frac{m_1m_2}{d} +k_1*m_1+a_1)
    所以,我们将两个方程合并为一个方程,我们重新令(m_1 = lcm(m_1,m_2), k_1 = k_1*m_1 +a_1)
    ------------恢复内容开始------------

    线性筛素数

    int pj[N], cnt, vis[N];
    
    void get_primes(int n) {
    	for(int i = 2; i <= n; i ++) {
    		if(!vis[i])	   pj[++ cnt] = i;
    		for(int j = 1; pj[j] * i <= n; j ++) {
    			vis[pj[j] * i] = true;
    			if( i % pj[j] == 0)    break; 
    		} 
    	}
    } 
    

    唯一分解定理:(x = prod p_{i} ^ {a_{i}})

    约数个数定理: (prod (a_i + 1))

    约数个数和定理: (prodsum_{i = 0}^{a_i}p_j^i)

    最大公约数: (gcd(a,b) = gcd(b, a mod b))

    线性筛phi

    (φ(n) = N prod (1 - frac{1}{p_i}))

    void get_primes(int n) {
        phi[1] = 1;
        for(int i = 2; i <= n; i ++) {
    	if(!vis[i])	   primes[++ cnt] = i, phi[i] = i - 1;
    	for(int j = 1; primes[j] * i <= n; j ++) {
    	    vis[primes[j] * i] = true;
    	    if( i % primes[j] == 0) {
    	    phi[i * primes[j]] = phi[i] * primes[j];
    	    break; 
    	}
    	phi[i * primes[j]] = phi[i] * (primes[j] - 1);
        }
    } 
    

    欧拉定理:

    [a ^{φ(n)} equiv 1 quad(mod n) ]

    其中,((a,n)=1)

    证明:
    引入一个概念: 缩系

    [R_n = {c_1, c_2, c_3, .... .c_{φ(n)} }, quad (c_i, n) = 1 ]

    同时乘上a, 也是mod n 的一个缩系,因为乘上a之后,两两互不同余,并且仍然与n互质。

    [prod_{i = 1}^{φ(n)}c_i equiv prod_{i = 1}^{φ(n)}ac_i ]

    [prod_{i = 1}^{φ(n)}c_i equiv a^φ(n) prod_{i = 1}^{φ(n)}c_i ]

    两边约去公因数,得到欧拉定理。

    如果 (n)为素数, 可以得到 费马小定理

    [a^{p - 1} equiv 1quad(mod p) ]

    由此,可以得到

    [a * a^{p - 2} equiv 1quad(mod p) ]

    所以,如果模数是素数,那么a的逆元就是(a^{p-2}),可以用快速幂求。

    扩展欧几里得exgcd:

    exgcd求解方程

    [ax +b y = gcd(a,b) ]

    由于

    [gcd(a,b) = gcd(b,a mod b) ]

    所以,我们可以写成和上面的方程一样的形式:

    [b x + (a mod b)y = gcd(a,b) ]

    进一步化简

    [bx + (a - lfloor frac{a}{b} floor b)y = gcd(a, b) ]

    [ay + b(x - lfloor frac{a}{b} floor y) = gcd(a, b) ]

    所以

    [x' = y, y' = x - lfloor frac{a}{b} floor y ]

    通解

    [x_k = x_0 + frac{kb}{gcd(a, b)}, y_k = x_0 - frac{ka}{gcd(a, b)} ]

    代码:

    void exgcd(int& x, int& y, int a, int b) {
    	if(!b) {
    		x = 1, y = 0;
    		return; 
    	} 
    	exgcd(y, x, b, a % b);
    	y -= (a / b) * x;
    }
    
    

    中国剩余定理

    给定 (2n) 个整数(a_1,a_2,…,a_n)(m_1,m_2,…,m_n,)求一个最小的非负整数 (x),满足(∀i∈[1,n],x≡m_i(mod a_i))并且模数两两互质。
    首先,设

    [M = prod_{i = 1}{n} b_i ]

    [m_i = frac{M}{bi} ]

    求解

    [m_i * m_i^{-1} equiv 1 ]

    [x = sum_{i = 1}^{n}a_i * m_i * m_i^{-1} ]

    for(int i = 1; i <= n; i ++) {
    	scanf("%lld%lld", &mo[i], &re[i]);
    	M *= mo[i];
    }
    for(int i = 1; i <= n; i ++) {
    	m[i] = M / mo[i];
    	LL tmp;
    	exgcd(inv[i], tmp, m[i], mo[i]);
    }
    LL ans = 0;
    for(int i = 1; i <= n; i ++) {
    	ans += (re[i] * m[i] * inv[i]);
    }
    printf("%lld
    ", (ans % M + M) % M); 
    

    扩展中国剩余定理exCRT

    首先考虑两个方程,
    (x ≡ a_1(mod m_1))

    (x ≡ a_2(mod m_2))

    进一步,写成等式:
    (x = k_1 * m_1 + a_1)
    (x = k_2 *m_2 + a_2)
    两式相等,得到:
    (k_1 *m_1-k_2*m_2 = a_1-a_2)
    只有(k_1)(k_2)是未知数,可以用exgcd进行求解。
    (d = gcd(m_1, m_2)),那么,(k_1)的通解为(k_t = k_1 + t * frac{m_2}{gcd(m_1,m_2)})
    所以(x = k_t * m_1 +a_1 = t * frac{m_1m_2}{d} +k_1*m_1+a_1)
    所以,我们将两个方程合并为一个方程,我们重新令(m_1 = lcm(m_1,m_2), k_1 = k_1*m_1 +a_1)

    scanf("%lld%lld", &m1, &a1);
    n --;
    LL x, m;
    while(n --) {
           	scanf("%lld%lld", &m2, &a2);
    	LL k1, k2;
    	LL d = exgcd(k1, k2, m1, m2);
    	if( (a2 - a1) % d) {
    		x = -1;
    		break;
    	}
    	k1 *= (a2 - a1) / d;//注意,这里是a2 - a1,不是a1 - a2,这里要跟exgcd的系数对应。
    	k1 = (k1 % (m2 / d) + m2 / d`) % (m2 / d);
    	x = k1 * m1 + a1;
    	a1 = k1 * m1 + a1;
    	m = m1 / d * m2;
    	m1 = m;
    }
    if( x != -1) 
        x = (x % m + m) % m;
    

    组合计数

    组合数递推:

    [{n choose k}={n - 1 choose k}+{n-1 choose k-1} ]

    void Com(int n, int m) {
            C[0][0] = 1;
    	for(int i = 1; i <= n; i ++) {
    		C[i][0] = 1;
    		for(int j = 1; j <= m; j ++) 
    		    C[i][j] = (C[i - 1][j] % p + C[i - 1][j - 1] % p) % p;
    	}
    }
    

    [(frac{1}{i!} ) ^{-1} = (frac{1}{(i - 1)!} )^{-1} * i ^ {-1 } ]

    fact[0] = infact[0] = 1;
    for(int i = 1; i < N - 99; i ++) {
    	fact[i] = (LL)fact[i - 1] * i % p;
            infact[i] = (LL)infact[i - 1] * qmi(i, p - 2) % p;
    }
    

    Lucas定理:

    [{a choose b} equiv{a mod p choose bmod p}{lfloor frac{a}{p} floor choose lfloor frac{b}{p} floor}(mod p) ]

    复杂度(O(p + log_pn))

    LL C(LL a, LL b, LL p) {
        return fac[a] * inv[b] % p * inv[a - b] % p;
    }
    LL Lucas(LL a, LL b, LL p)
    {
    	if( a < p && b < p)
    	    return C(a, b, p);
    	return Lucas(a / p, b / p, p) * Lucas(a % p, b % p, p) % p;
    }
    
  • 相关阅读:
    数组作为函数参数传递时
    Tree 笨方法实现
    双向链表
    带头节点的循环链表及两个循环链表的合并
    josephus问题->不带头节点的循环链表
    数组形式链表
    检测qq是否在线
    Python-requests模块
    Python面向对象练习——基于面向对象设计一个对战游戏
    Python-面向对象
  • 原文地址:https://www.cnblogs.com/wyy0804/p/13591534.html
Copyright © 2011-2022 走看看