基础数学知识

本文介绍了多种数论算法,包括质数判断(试除法)、质因数分解、素数筛法(朴素筛法、线性筛法)以及与约数相关的计算,如求约数、约数个数、约数之和、欧拉函数等。同时,还涉及了最大公约数的计算和扩展欧几里得算法的应用。
摘要由CSDN通过智能技术生成

质数

一个大于 1 的自然数,如果除了 1 和它自身外,不能被其他自然数整除则称该数为质数。

试除法判定质数

质数

#include <iostream>

using namespace std;

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

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int x;
        cin>>x;
        if (is_prime(x)) cout<<x<<" "<<"is prime"<<endl;
        else cout<<x<<" "<<"is not prime"<<endl;
    }
}

质因数分解

将每个数分解质因数,并按照质因数从小到大的顺序输出每个质因数的底数和指数。

输入样例:
2
6
8

输出样例:
2 1
3 1
(空行)
3 1

#include <iostream>

using namespace std;

void divide(int x)
{
    for (int i=2;i<=x/i;i++)
        if (x%i==0)
        {
            int s=0;
            while(x%i==0) x/=i, s++;
            cout<<i<<' '<<s<<' '<<endl;
        }
    if (x>1) cout<<x<<' '<<1<<endl;//较大的一个素数
}

int main()
{
    int n;
    cin>>n;
    while(n--)
    {
        int x;
        cin>>x;
        divide(x);
        cout<<endl;
    }
}

朴素筛法求素数

素数个数

#include <iostream>

using namespace std;

const int N=1e6+10;

int cnt;
bool st[N];//判断是否被筛掉

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

int main()
{
    int n;
    cin>>n;
    get(n);
    cout<<cnt<<endl;
}

线性筛法求素数

素数个数

#include <iostream>

using namespace std;

const int N=1e8+10;

int cnt;
int prime[N];//存储所有素数
bool st[N];//判断是否被筛掉

void get(int n)
{
    for (int i=2;i<=n;i++)
    {
        if (st[i]==0) 
        {
            prime[cnt]=i;
            cnt++;
        }
        for (int j=0;prime[j]<=n/i;j++)
        {
            st[prime[j]*i]=true;
            if (i%prime[j]==0) break;//防止重复筛掉
        }
    }
}

int main()
{
    int n;
    cin>>n;
    get(n);
    cout<<cnt<<endl;
}

约数

试除法求约数

一共n个正整数,从小到大输出每个数ai的所有约数
1<=n<=100
2<=ai<=2*10^9

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N=2e6+10;

int prime[N];

void get(int n)
{
    
    memset(prime, 0, sizeof prime);
    int idx=0;
    for (int i=1;i<=n/i;i++)
    {
        if (n%i==0) prime[idx++]=i;
        if (i!=n/i) prime[idx++]=n/i;
    }
    sort(prime,prime+idx);
    for (int i=0;i<idx;i++)
    {
        cout<<prime[i]<<' ';
    }
    cout<<endl;
}

int main()
{
    int n;
    cin>>n;
    while (n--)
    {
        int x;
        cin>>x;
        get(x);
    }
}

约数个数和约数之和

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)

约数个数

给定n个正整数ai ,输出这些数的乘积的约数个数,答案对1e9+7取模
1<=n<=100
1<=ai<=2*10^9

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mod=1e9+7, N=1e8+10;

int b[N];//存储指数
LL cnt=1;

int main()
{
    int n;
    cin>>n;
    int maxx=0;
    
    while(n--)
    {
        int x;
        cin>>x;
        for (int i=2;i<=x/i;i++)
        {
            while(x%i==0)
            {
                x/=i;
                b[i]++;
                maxx=max(maxx,i);
            }
        }
        if (x>1) b[x]++, maxx=max(maxx,x);
    }
    
    for (int i=0;i<=maxx;i++)
        if (b[i]) cnt=cnt*(b[i]+1)%mod;
        
    cout<<cnt;
}

约数之和

给定n个正整数ai ,输出这些数的乘积的约数之和,答案对1e9+7取模
1<=n<=100
1<=ai<=2*10^9

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;

const int mod=1e9+7, N=1e8+10;

int b[N];//存储底数和指数,b[i]=j,i为底数,j为指数
LL sum=1;

int main()
{
    int n;
    cin>>n;
    int maxx=0;
    
    while(n--)
    {
        int x;
        cin>>x;
        for (int i=2;i<=x/i;i++)
        {
            while(x%i==0)
            {
                x/=i;
                b[i]++;
                maxx=max(maxx,i);
            }
        }
        if (x>1) b[x]++, maxx=max(maxx,x);
    }
    
    for (int i=0;i<=maxx;i++)
    {
        if (b[i])
        {
            LL t=1;
            while(b[i]--)
            {
                t=(t*i+1)%mod;
            }
            sum=sum*t%mod;
        }
    }
        
    cout<<sum;
}

欧拉函数

欧几里得算法

最大公约数

#include <iostream>

using namespace std;

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

int main()
{
    int a,b;
    cin>>a>>b;
    cout<<gcd(a,b);
}

求欧拉函数

欧拉函数:1到n中与n互质的数的个数
n分解质因数:n=p1^c1 * p2^c2 * … * pk^ck
则个数为 n * (1-1/p1) * (1-1/p2) * … * (1-1/pk)

给定n个正整数ai,求每个数的欧拉函数
1<=n<=100
1<=ai<=2*10^9

#include <iostream>

using namespace std;

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 main()
{
    int n;
    cin>>n;
    
    while(n--)
    {
        int x;
        cin>>x;
        cout<<phi(x)<<endl;
    }
}

筛法求欧拉函数

求1-n中每个数的欧拉函数之和
1<=n<=10^6

#include <iostream>

using namespace std;

typedef long long LL;

const int N=1e6+10;

int n;
int prime[N],cnt;//prime[]存储所有素数
int euler[N];//存储每个数的欧拉函数
bool st[N];

void get_euler(int n)
{
    euler[1]=1;
    
    for (int i=2;i<=n;i++)
    {
        if (st[i]==false)
        {
            prime[cnt++]=i;
            euler[i]=i-1;//质数的欧拉函数
        }
        for (int j=0;prime[j]<=n/i;j++)
        {
            int t=prime[j]*i;
            st[t]=true;
            if (i%prime[j]==0)
            {
                euler[t]=euler[i]*prime[j];
                break;
            }
            euler[t]=euler[i]*(prime[j]-1);
        }
    }
}

int main()
{
    int n;
    cin>>n;
    
    get_euler(n);
    
    LL ans=0;
    for (int i=1;i<=n;i++)
        ans+=euler[i];
        
    cout<<ans;
}

快速幂

【模板】快速幂||取余运算

#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long LL;

LL qmi(LL a, LL b, LL p)
{
    LL res=1%p, base=a;
    while(b)
    {
        if (b & 1) res=res*base%p;
        base=base*base%p;
        b>>=1;
    }
    return res;
}

int main()
{
    LL a,b,p;
    scanf("%lld%lld%lld",&a,&b,&p);
    printf("%lld^%lld mod %lld=",a,b,p);
    printf("%lld",qmi(a,b,p));
}

扩展欧几里得算法

题目描述
给定n对正整数ai,bi,对于每对数,求出一组xi,yi,使其满足aixi+biyi=gcd(ai,bi)。

输入格式
第一行包含整数n。
接下来n行,每行包含两个整数ai,bi。

输出格式
输出共n行,对于每组ai,bi,求出一组满足条件的xi,yi,每组结果占一行。

本题答案不唯一,输出任意满足条件的xi,yi均可。

数据范围
1≤n≤10^5
1≤ai,bi≤2∗10^9

输入样例:
2
4 6
8 18
输出样例:
-1 1
-2 1

#include <iostream>
#include <algorithm>

using namespace std;

int exgcd(int a, int b, int &x, int &y)//返回x,y的值
{
    if (b==0)
    {
        x=1,y=0;
        return a;
    }
    
    int d=exgcd(b, a%b, x, y);
    int temp=x;
    x=y;
    y=temp-(a/b)*y;
    return d;
}

int main()
{
    int n;
    cin>>n;
    
    while(n--)
    {
        int a,b,x,y;
        cin>>a>>b;
        
        exgcd(a,b,x,y);
        
        cout<<x<<' '<<y<<endl;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值