数学部分

质数

在大于1的整数中,如果只包含1和本身这两个约数,就被称为质数,或者叫素数。

1.质数的判定(试除法)

时间复杂度 O ( n ) O(\sqrt{n})

如果d|n,则 n d n \frac{n}{d} | n ,则 d n d d \leq \frac{n}{d}
模板

bool is_prime(int x)
{
    if (x < 2) return false;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
            return false;
    return true;
}

2.分解质因数(试除法)

时间复杂度 O ( n ) O(\sqrt{n})
n中最多只包含一个大于> n \sqrt{n} 的质因子。
模板

void divide(int x)
{
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)  //i一定是质数
        {
            int s = 0;  //s是i的一个次数
            while (x % i == 0) x /= i, s ++ ;
            cout << i << ' ' << s << endl;
        }
    if (x > 1)  //当x大于1的时候,说明x就是那个唯一大于sqrt(n)的质因子
    	cout << x << ' ' << 1 << endl;
    cout << endl;
}

3.朴素筛法求素数

模板

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (st[i]) continue;
        primes[cnt ++ ] = i;
        for (int j = i; j <= n; j += i)
            st[j] = true;
    }
}

4.线性筛法求素数

模板

int primes[N], cnt;     // primes[]存储所有素数
bool st[N];         // st[x]存储x是否被筛掉

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i]) primes[cnt ++ ] = i;
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0) break;
        }
    }
}

5.试除法求所有约数

一个数 n n 的约数都是成对出现的,即 i i 对应 n / i n/i ,但有一种情况要特判 i i = n i * i = n
模板

vector<int> get_divisors(int x)
{
    vector<int> res;
    for (int i = 1; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res.push_back(i);
            if (i != x / i) res.push_back(x / i);
        }
    sort(res.begin(), res.end());
    return res;
}

6.约数个数和约数之和

模板

如果 N = p1^c1 * p2^c2 * ... *pk^ck
约数个数: (c1 + 1) * (c2 + 1) * ... * (ck + 1)
约数之和: (p1^0 + p1^1 + ... + p1^c1) * ... * (pk^0 + pk^1 + ... + pk^ck)

7.欧几里得算法

模板

int gcd(int a, int b)
{
    return b ? gcd(b, a % b) : a;
}

8.欧拉函数

互质是公约数只有1的两个整数,叫做互质整数。 公约数只有1的两个自然数,叫做互质自然数。
ϕ ( n ) \phi (n) :1 ~ n中与n互质的数的个数。

1 2 3 4 5 6
1,5和6互质

ϕ ( 6 ) \phi (6) =2

1.分解质因数 N = p 1 a 1 p 2 a 2 . . . p k a k N = p_{1}^{a_{1}}*p_{2}^{a_{2}}...p_{k}^{a_{k}}

2.求欧拉函数 ϕ ( N ) = N ( 1 1 p 1 ) ( 1 1 p 2 ) . . . ( 1 1 p k ) \phi (N) = N(1-\frac{1}{p_{1}})(1-\frac{1}{p_{2}})...(1-\frac{1}{p_{k}})
该式就是求1 ~ n中与 n n 互质的数的个数。
通过容斥原理推出该式
在这里插入图片描述

求欧拉函数
模板

int phi(int x)
{
    int res = x;
    for (int i = 2; i <= x / i; i ++ )
        if (x % i == 0)
        {
            res = res / i * (i - 1);
            while (x % i == 0) x /= i;
        }
    if (x > 1) res = res / x * (x - 1);

    return res;
}

#include <iostream>
#include <algorithm>

using namespace std;

int main(){

    int n;
    cin >> n;
    while(n--){
        int a;
        cin >> a;
        int res = a;
        for(int i = 2;i <= a/i;i++){
            if(a % i == 0){
                res = res / i * (i - 1);
                while (a % i == 0)
                    a /= i;
            }
        }
        if(a > 1)
            res = res / a * (a - 1);
        cout << res << endl;
    }


    return 0;
}

筛法求欧拉函数
模板

int primes[N], cnt;     // primes[]存储所有素数
int euler[N];           // 存储每个数的欧拉函数
bool st[N];         // st[x]存储x是否被筛掉


void get_eulers(int n)
{
    euler[1] = 1;
    for (int i = 2; i <= n; i ++ )
    {
        if (!st[i])
        {
            primes[cnt ++ ] = i;
            euler[i] = i - 1;
        }
        for (int j = 0; primes[j] <= n / i; j ++ )
        {
            int t = primes[j] * i;
            st[t] = true;
            if (i % primes[j] == 0)
            {
                euler[t] = euler[i] * primes[j];
                break;
            }
            euler[t] = euler[i] * (primes[j] - 1);
        }
    }
}

9.欧拉定理

a a n n 互质,则 a ϕ ( n ) 1 ( m o d a^{\phi(n)} \equiv1(mod n)

10.乘法逆元

求a % p的乘法逆元

若整数b,m互质,并且b|a,则存在一个整数 x x ,使得 a / b a x ( m o d m ) a/b\equiv a * x(mod m) ,则称x为b的模m乘法逆元,记为 b 1 ( m o d m ) b^{-1}(mod m)
b 存在乘法逆元的充要条件是b与模数m互质。当模数m为质数时, b m 2 b^{m-2} 即为b的乘法逆元。

a b a x ( m o d \frac{a}{b}\equiv a \cdot x(mod m)
b b 1 1 ( m o d b \cdot b^{-1}\equiv1(mod m)
b x 1 ( m o d b \cdot x\equiv1(mod m)

x表示逆元

费马定理

b p 1 1 ( m o d b^{p-1}\equiv1(mod p)
b b p 2 1 ( m o d b \cdot b^{p-2}\equiv1(mod p)

综上推导,求b % p(质数)的逆元就是求 b p 2 b^{p-2} ,如果b是p的倍数则无解,其他情况有解。

#include<iostream>

using namespace std;

typedef long long ll;

ll quick_pow(ll a, ll b, ll p) {
	ll ans = 1 % p;
	while (b) {
		if (b & 1)
			ans = ans * a % p;
		a = a * a % p;
		b >>= 1;
	}
	return ans;
}

int main() {

	int n;
	cin >> n;
	while (n--) {
		int a, p;
		cin >> a >> p;
		if (p >= 2 && a % p != 0)
			cout << quick_pow(a, p - 2, p) << endl;
		else
			puts("impossible");
	}

	return 0;
}

11.裴蜀定理

对于任意正整数 a , b a,b ,那么一定存在非零整数 x , y x,y ,使得 a x + b y = g c d ( a , b ) ax + by = gcd(a,b)

#include<iostream>

using namespace std;

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

int main() {

	int n;
	scanf("%d", &n);
	
	while (n--) {
		int a, b,x,y;
		scanf("%d%d", &a, &b);
		ex_gcd(a, b, x, z
		printf("%d %d\n", x, y);
	}

	return 0;
}

12.中国剩余定理

13.高斯消元

求解多元线性方程组
在这里插入图片描述
解的分布:

  1. 无解
  2. 有唯一解
  3. 无穷多组解

在这里插入图片描述
算法步骤:

  1. 把某一行乘一个非零的数
  2. 交换某两行
  3. 把某行的若干倍加到另一行上

在这里插入图片描述

  1. 完美阶梯形-------唯一解
  2. 0=非零 -------无解
  3. 0=0 --------无穷多组解

14.容斥原理

从n个数中选任意多个数的方案数
在这里插入图片描述
acwing890.能被整除的数

在这里插入图片描述

发布了52 篇原创文章 · 获赞 5 · 访问量 2256

猜你喜欢

转载自blog.csdn.net/advjj_058229/article/details/100674578