数论:欧几里得算法;欧几里得扩展式;欧拉函数, 欧拉筛选;积性函数;费马小定理;欧拉定理;欧拉定理的推论;线性同余方程;中国剩余定理

28 篇文章 0 订阅
7 篇文章 0 订阅
  1. 欧几里得算法

        对任意整数a, b 并且 b不等于0, 有 gcd(a, b) = gcd(b, a % b)

代码

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

朴素写法

int gcd(int a, int b){
	if(b == 0) return a;
	return gcd(b, a % b);
}
  1. 欧几里得扩展式

        对于任意整数a, b, 存在一对整数x, y, 满足ax + by =gcd(a, b), 程序求出方程的一组特解, x*, y*, 并且返回a, b的最大公约数 d。
代码

int exgcd(int a, int b, int &x, int &y){
	if(b == 0){
		x = 1;
		y = 0;
		return a;
	}
	int d = exgcd(b, a % b, x, y);
	int z = x;
	x = y;
	y = z - y * (a / b);
	return d;
}
  1. 欧拉函数

       在学习欧拉函数之前我们学习互质的定义: 对两个正整数a, b ,若gcd(a, b) = 1, 则称a, b互质。
        欧拉函数:1 - N 中与 N 互质的数的个数被称为欧拉函数,记为 φ(N), 在算术基本定理中, N = p1 ^ c1 * p2 ^ c2 …*pm ^ cm, 则可以把欧拉函数记做:
        φ(N) = N * (p1 - 1) / p1 * (p2 - 1) / p2 * … *(pm - 1) / pm

        欧拉函数有两个性质:

  1. 对于任意 n > 1, 在1 - n 中与 n 互质的数的和为 n * φ(n) / 2
  2. 若 a, b 互质, 则φ(a*b) = φ(a) * φ(b)
  3. 积性函数
            如果 a, b 互质时有:f(a*b) = f(a) * f(b), 那么称 f 为积性函数
  4. 若 f 是积性函数, 且在算术基本定理中 n = p1 ^ c1 * p2 ^ c2 * … * pm^cm, 则有 f(n) =    f(p1 ^ c1) * f(p2 ^ c2) * … * f(pm ^ cm)

代码

int p(int n){
	int ans = n;
	for(int i = 2; i <= sqrt(n); i++){
		if(n % i == 0){
			ans = ans / i * (i - 1);  // φ(N) 
			while(n % i == 0) n /= i; //把i这个质因数去掉
		}
	}
	if(n > 1) ans = ans / n * (n - 1);
	return ans;
}
  1. 欧拉筛选

利用Eratosthenes筛法求出欧拉函数 p[n] 存的 n 的欧拉函数
代码

O(n^2)

int p[1010];
void g(int n){  //欧拉筛选
    for(int i = 2; i <= n; i++)
        p[i] = i;
    for(int i = 2; i <= n; i++){
        if(p[i] == i){
            for(int j = i; j <= n; j += i){
                p[j] = p[j] / i * (i - 1);
            }
        }
    }
}

O(n)

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1e6 + 10;
int n, cnt ;
int prime[N], phi[N];
bool vis[N];

long long euler(int n)
{
    phi[1] = 1;
    for (int i = 2; i <= n; i++)
    {
        if (!vis[i])
        {
            phi[i] = i - 1;
            prime[cnt++] = i;
        }
        for (int j = 0; prime[j] <= n / i; j++)
        {
            vis[i * prime[j]] = true;
            if (i % prime[j] == 0)
            {
                phi[prime[j] * i] = prime[j] * phi[i];
                break;
            }
            phi[prime[j] * i] = (prime[j] - 1) * phi[i];
        }
    }
    long long ans = 0;
    for (int i = 1; i <= n; i++)
    {
        ans += phi[i];
    }
    return ans;
}

int main()
{
    cin.tie(0);
    ios::sync_with_stdio(false);
    cin >> n;
    cout << euler(n) << endl;
    return 0;
}
  1. 费马小定理

        若 p 是质数, 则对于任意整数 a , 有 a^p ≡ a (mod p), 即是 a^p 与 a 同余

  1. 欧拉定理

        若正整数 a, n 互质, 则 a^φ(n) ≡ 1 (mod n), 即是 a^φ(n) % n = 1

  1. 欧拉定理的推论

       1. 若正整数 a, n 互质, 则对于任意的正整数 b, 有 a^b ≡ a ^(b mod φ(n)) (mod n)

       2. 当 a, n 不一定互质且 b > φ(m) 时,有a^b ≡ a^(b mod φ(n) + φ(n)) (mod n)。

       许多计数类的题目要求我们把答案对一个质数 p 取模后输出。面对a+b,a-b,a*b 这样的算式,可以在计算前先把a,b对p取模。面对乘方算式,根据欧拉定理的推论,可以先把底数对p取模、指数对φ( p ) 取模,再计算乘方。

  1. 线性同余方程

       已知a, b, m, 求x, 满足方程 a * x ≡ b (mod m) 我们称它为线性同余方程
        a * x ≡ b( mod m)等价于 a * x - b 是 m 的倍数,不妨设为 -y 倍。于是,该方程可以改写为 a * x + m * y = b方程有解的当且仅当gcd(a, m) | b.

       同余方程练习题:NOIP2012/CH3301 同余方程
题目描述
求关于x的同余方程 ax ≡ 1(mod b) 的最小正整数解。
输入格式
输入只有一行,包含两个正整数a,b,用一个空格隔开。
输出格式
输出只有一行,包含一个正整数x,表示最小正整数解。
输入数据保证一定有解。
数据范围
2≤a,b≤2∗109

输入样例:
3 10
输出样例:
7

代码

#include<iostream>
using namespace std;
typedef long long ll;
ll a, b, x, y;
ll exgcd(ll a, ll b, ll &x, ll &y){
    if(b == 0){
        x = 1;
        y = 0;
        return a;
    }
    ll d = exgcd(b, a % b, x, y);
    ll z = x;
    x = y;
    y = z - y * (a / b);
    return d;
}
int main(){
    cin >> a >> b;
   
    cout << exgcd(a, b, x, y) << endl;
    return 0;
}
  1. 中国剩余定理

       设 m1 , m2,… mn 是两两互质的整数,m = m1 * m2 * … * mn,Mi = m / mi, ti 是线性同余方程 Mi * ti ≡ 1 (mod mi) 的一个解。对于任意的n个整数a1,a2,…,an, 方程组
       x ≡ a1 (mod m1)
       x ≡ a2( mod m2)
       …
       x ≡ = an ( mod mn)
有整数解,解为x = (a1 * M1* t1) + (a2 * M2* t2) + …+ (an * Mn* tn)。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值