加载中...

数论

质数

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


(1)质数的判定——试除法
//试除法判定质数模板
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;
}
注意:循环的结束条件为 i<=x/i ,若改为 i*i<=x 在x接近int上界时会有溢出风险

(2)分解质因数——试除法
//试除法分解质因数模板
void divide(int x)
{
    for(int i=2;i<=x/i;i++)
        if(x%i==0)
        {
            int s=0;
            while(x%i==0)
            {
                s++;
                x/=i;
            }
            cout<<i<<' '<<s<<'\n';
        }
    if(x>1)cout<<x<<' '<<1<<'\n';
    //n中最多只含一个大于sqrt(n)的质因子
}

(3)质数的判定——埃氏筛法
//朴素筛法求素数模板

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

void get_primes(int n)
{
    for(int i=2;i<=n;i++)
    {
        if(st[i])continue;
        primes[cnt++]=i;
        for(int j=i+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[j])primes[cnt++]=i;
        for(int j=0;primes[j]<=n/i;j++)
        {
            st[primes[j]*i]=true;
            if(i%primes[j]==0)break;
            //primes[j]一定是i的最小质因子
        }
    }
}



约数

(1)试除法求一个数的所有约数
//试除法求所有的约数模板
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;
}

(2)约数个数
(3)约数之和

如果 N = \(p^{c_1}_{1}\) × \(p1^{c_2}_{2}\) × \(\cdots\) × \(p^{c_k}_k\)

约数个数: (\(c_1\) + 1) × (\(c_2\) + 1) × \(\cdots\) × (\(c_k\) + 1)

约数之和: (\(p^0_1\) + \(p^1_1\) + \(p^2_1\) + \(\cdots\) + \(p^{c_1}_1\)) × (\(p^0_2\) + \(p^1_2\) + \(p^2_2\) + \(\cdots\) + \(p^{c_2}_2\)) × \(\cdots\) × (\(p^0_k\) + \(p^1_k\) + \(\cdots\) + \(p^{c_k}_k\) )


//求约数个数模板

unordered_map<int,int>primes;

while(n--)
{
    int x;
    cin>>x;
    
    for(int i=2;i<=x/i;i++)
        while(x%i==0)
        {
            x/=i;
            primes[i]++;
        }
    if(x>1)primes[x]++;
}
long long res=1;
for(auto p:primes)res=res*(p.second+1)%mod;

//求约数之和模板

unordered_map<int,int>primes;

while(n--)
{
    int x;
    cin>>x;
    
    for(int i=2;i<=x/i;i++)
        while(x%i==0)
        {
            x/=i;
            primes[i]++;
        }
    if(x>1)primes[x]++;
}

long long res=1;
for(auto p:primes)
{
    long long a=p.first,b=p.second;
    long long t=1;
    while(b--)t=(t*a+1)%mod;
    res=res*t%mod;
}

(4)欧几里得算法(辗转相除法)

原理: d 能整除 a , d 能整除 b \(\longrightarrow\) 则 d 能整除 ax+by

  • a % b = a - [ \(\dfrac{a}{b}\) ] × b = a - c × b

  • a 和 b的最大公约数

    = b 和 a - c × b 的最大公约数

    = b 和 a % b 的最大公约数


//欧几里得算法
int gcd(int a,int b)
{
    return b?gcd(b,a%b):a;
}



欧拉函数

欧拉函数 \(\varphi\) (n) 1 ~ n 中与n互质的数的个数

如果 N = \(p^{\alpha_1}_1\) × \(p^{\alpha_2}_2\) × \(\cdots\) × \(p^{\alpha_k}_k\)

\(\varphi\) (N) = N × (1 - \(\dfrac{1}{p_1}\)) × (1 - \(\dfrac{1}{p_2}\)) × \(\cdots\) × (1 - \(\dfrac{1}{p_k}\))


//公式法求欧拉函数模板
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;
}

//筛法求欧拉函数模板

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

void get_eulers(int n)
{
    eular[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);
        }
    }
}

欧拉定理: 若 a 与 n 互质, 则 \(a^{\varphi~(n)~}\) % n = 1

费马定理: 若 a 与 p 互质, p为质数, 则 \(a^{p-1}\) % p = 1




快速幂

快速幂: 用 O(log2k)时间计算出 \(a^k\) mod p

算法原理: 先预处理出

\[\begin{cases} a^{2^0} \text{ mod p}\\[0.3ex] a^{2^1} \text{ mod p} \quad\quad\quad\quad \text{$a^{2^1}$ = $a^{2^{0}*2}$ = $(a^{2^0})^{2}$}\\[0.3ex] a^{2^2} \text{ mod p} \quad\quad\quad\quad \text{$a^{2^2}$ = $a^{2^{1}*2}$ = $(a^{2^1})^{2}$}\\[0.3ex] \quad\quad \cdots \\[0.3ex] a^{2^{log_{2}k}} \text{ mod p} \quad\quad\quad \text{$a^{2^{log_{2}k}}$ = $(a^{2^{log_{2}k}-1})^{2}$}\\[0.3ex] \end{cases} \]

\(a^k\) = \(a^{2^{x_1}}\) * \(a^{2^{x_2}}\) \(\cdots\) \(a^{2^{x_t}}\)

​ = \(a^{2^{x_1}+2^{x_2}+2^{x_3}+\cdots+2^{x_t}}\)


//快速幂模板
//求 (m^k)%p

int qmi(int m,int k,int p)
{
    int 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 = gcd (a, b)


//扩展欧几里得算法模板
//求x,y,使得ax+by=gcd(x,y)

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,y,x);
    y-=(a/b)*x;
    return d;
}


posted @ 2023-04-29 01:49  邪童  阅读(13)  评论(0编辑  收藏  举报