算法之路--数论(1)

本文介绍了数论中的几个基础概念和算法,包括质数的判定(试除法、埃式筛法、线性筛法)、分解质因数、求解约数个数和和、最大公约数的欧几里得算法、欧拉函数以及快速幂和扩展欧几里得算法的应用。这些算法在计算数学和密码学等领域有重要应用。
摘要由CSDN通过智能技术生成

一、质数(素数)

从2开始,只有1和它本身的数叫做素数

1.质数的判定--试除法 ( O(N^1/2)

for(int i =2 ;i<=n/i ;i++)

2.分解质因数--试除法(O(logN~N^1/2))

void divide(int x)
{
  for(int i =2 ;i<= n/i ;i++)
    if(x%i==0)
    {
        int s = n ;
        while(x%i==o) x/=i,s++;
        cout<<i<<' '<<s<<endl;
    }
    if(x>1) cout<<x<<' '<<1<<endl;
}

3.筛选质数--埃式筛法

原理:依次枚举i,将i的倍数全部删除,剩下的序列就是素数的序列

int prines[N],cnt;  //存素数
bool st[N];        //判断是否需要筛除 true表示筛除

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

由于以上算法在进行筛除元素的时候会有重复的操作,于是我们改进了一个算法,解决了该问题。

改进--线性筛算法--O(NN)

算法原理:

  1. 从小到大枚举i

  1. 如果当前数没被划掉,必然是质数,记录下来

  1. 枚举已经被记录的质数(如果该质数与i的合数越界,循环中断)->i*primes【j】

a.合数未越界,则划掉合数,继续循环

b.条件:i%primes【j】==0 可以保证合数只被最小质因子划掉,保证了不会重复,是该算法的核心

1.若i是质数,则循环最多可以枚举到本身

2.若i是合数,则最多可以枚举到自身的最小质数后中断循环

int prines[N],cnt;  //存素数
bool st[N];        //判断是否需要筛除 true表示筛除

void get_prinmes(int n)
{
    for(int i = 2 ;i<=n/i; 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;
        }
    }
}

二、约数

约数,又称因数整数a除以整数b(b≠0) 除得的商正好是整数而没有余数

1.求一个数的所有约数--试求法

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

如果 N= P1^C1 * P2^C2 * ... * Pk^Ck;

2.求约数的个数:(c1=1)*(c2+1)*(c3+1)*...*(cK+1);

基本公式:所有质因数的指数加上1的积

3.求约数的和:(p1^0+p1^1+...+p1^c1)*...*(pk^0+pk^1+...+pk^ck)

基本公式:先把每一个质因数从0次幂加到最高次幂,再相乘

4.求最大公约数--欧几里得算法(辗转相除法)

基本原理:gcd(a,b) = gcd(b,a mod b)

int gcd(int a,int b)
{
    if(!b) return a;
    return gcd(b,a%b);
}

三、欧拉函数

给定一个n,求得1到n中与n互质的数的个数

基本公式:φ(n)=n * (1-1/P1) * (1-1/P2) * … * (1-1/Pn)

其中,φ(n)表示1~n中与n互质的个数,p表示质因数。

int phi(int n)
{
    int ans = n;
    for(int i = 2;i * i <= n;i++)//分解质因子
    {
        if(n % i == 0)
        {
            ans = ans / i * (i-1);
            //现在的i为质因子,根据公式(1-(1/i)),也就是乘以(i-1)/i  处理一下
            while(n % i == 0)
                n /= i;
        }
    }
    if(n > 1)
        ans = ans / n * (n-1);
    return ans;
}

四、快速幂算法--O(logK)

快速的求出a^k(mod)p的结果 速度快

基本原理:反复平方

例子:求3^10
1.   3^10    ---->    9^5
2.   9^5    ---->    9*9^4
3.   9*9^4    ---->   9*81^2
4.   9*81^2   ----> 6561*9
以上过程中会不断取模
long long  qmi(long long  m, long long  k,long long  p)   //求m^k(mod)p
{
    long long  res = 1% p,
    t = m;
    while(K)
    {
        if(k&1) res =res * t % p;
        t = t * t % p;
        k>>=1;
    }
    return res;
}

五、扩展欧几里得算法

【裴蜀定理】

对于任意一对正整数a,b。一定存在两个参数x,y。使得: ax + by = (a,b)最大公约数。

[例题] 给一个同余线性方程 aX = b(mod m)请你求出一个X满足该式

稍微处理以下 得到 ax + my = b 从定义出发,b必须是(a,m)的倍数方程有解

求解上述线性方程:

当b==0时,明显 X=1,Y=0是方程的一组特解

当b不等于0时,gcd(a,b) = gcd(b,a%b);代入方程

-->by + (a %b) x = d;

-->by + (a- (a/b)*b )x = d;

-->ax + b(y- (a/b) x)= d;

可以看出,经过一次变换后

x= y1 ;

y = x1 - (a/b) *y1 ;

#include<iostream>
#include<bits/stdc++.h>

using namespace std;
int exgcd(int a,int b,int x,int y)
{
    if(!b)
    {
        x=1,y=0;return a; 
    }
    int d = exgcd(b,a&b,y,x);
    y-=a/b*x;
    return d;
}
int main()
{

六、孙子定理(中国剩余定理)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值