第4讲 数学知识

试除法判定质数


#include<iostream>
using namespace std;

const int maxn=111;

int n;

bool isPrime(int x)
{
    if(x<2)                                 //注意x<2为return false
        return false;

    for(int i=2; i<=x/i; i++)        //i<=x/i
        if(x%i==0)
            return false;

    return true;
}

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
    {
        int temp;
        cin >> temp;

        if(isPrime(temp))
            cout << "Yes" << endl;
        else
            cout << "No" << endl;
    }

    return 0;
}

分解质因数


#include<iostream>
using namespace std;

const int maxn=111;

int n;

int divide(int x)
{
    for(int i=2; i<=x/i; i++)       //从2开始遍历数字
        if(x%i==0)          //如果x能求余i为0
        {
            int s=0;        //s统计i的个数
            while(x%i==0)
            {
                x/=i;
                s++;
            }
            cout << i << " " << s << endl;
        }
    //下面这个if不是在上面那个for中的
    if(x>1)     //如果此时x>1,表示剩下最后一个素数
            cout << x << " " << 1 << endl;
    cout << endl;
}

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
    {
        int x;
        cin >> x;          //输入要找的数字
        divide(x);
    }

    return 0;
}

晒素数

在这里插入图片描述

#include <iostream>
#include <algorithm>

using namespace std;

const int N= 1000010;

int primes[N], cnt;
bool st[N];

void get_primes(int n)
{
    for (int i = 2; i <= n; i ++ )       //i从2开始一直到n枚举
    {
        if (!st[i]) primes[cnt ++ ] = i;        //如果i为素数,则将i统计到primes中
        for (int j = 0; primes[j] <= n / i; j ++ )      //从小到大枚举所有的素数
        {
            st[primes[j] * i] = true;       //这个一定是存在的
            if (i % primes[j] == 0) break;      //如果i%primes[j]==0,表示primes[j]一定是i的最小素数
        }
    }
}

int main()
{
    int n;
    cin >> n;       //输入n,统计1——n的所有质数的个数

    get_primes(n);      

    cout << cnt << endl;

    return 0;
}





试除法求约数


#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

const int maxn=111;

int n;

vector<int> kkk(int x)
{
    vector<int> res;
    for(int i=1; i<=x/i; i++)
        if(x%i==0)                   //只要能让x%i==0,表示i就是x的约数
        {
            res.push_back(i);
            if(i!=x/i)
                res.push_back(x/i);
        }


    sort(res.begin(),res.end());

    return res;
}

int main()
{
    cin >> n;
    for(int i=0; i<n; i++)
    {
        int temp;
        cin >> temp;
        auto res=kkk(temp);

        for(auto item:res)
                cout << item <<  " ";

        cout << endl;
    }

    return 0;
}

约数个数

在这里插入图片描述


#include<iostream>
#include<unordered_map>
using namespace std;

const int maxn=111;
const int mod=1e9+7;

int n;

int main()
{
    cin >> n;

    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]++;        //注意这个数字是自增的,有可能是x会相同,所以还是要自增

    }

    long long res=1;       //res的值很大,所以设置为long long
    for(auto item:primes)
        res=res*(item.second+1)%mod;

    cout << res;

    return 0;

}

约数之和

在这里插入图片描述

#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <vector>

using namespace std;

typedef long long LL;

const int N = 110, mod = 1e9 + 7;

//需要这道题算出96的所有约数之和

int main()
{
    int n;
    cin >> n;           //输入n

    unordered_map<int, int> primes;         //设置primes

    while (n -- )
    {
        int x;
        cin >> x;           //输入x

        for (int i = 2; i <= x / i; i ++ )      //统计x的所有素数的个数
            while (x % i == 0)
            {
                x /= i;
                primes[i] ++ ;
            }

        if (x > 1) primes[x] ++ ;
    }

    LL res = 1;
    for (auto p : primes)           //用p去遍历primes
    {
        LL a = p.first, b = p.second;       //a是底数,b是指数
        LL t = 1;           //t表示为1
        while (b -- )           //这就是那个计算方法     
            t = (t * a + 1) % mod;          
        res = res * t % mod;
    }

    cout << res << endl;

    return 0;
}


欧拉函数

与n互质的数



#include <iostream>

using namespace std;


int phi(int x)
{
    int res = x;
    for (int i = 2; i <= x / i; i ++ )      //这相当于在找x的所有因数
        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;           //输入n
    while (n -- )
    {
        int x;
        cin >> x;       //输入x
        cout << phi(x) << endl;
    }

    return 0;
}

筛法求欧拉函数

#include <iostream>
#include <algorithm>

//两个数字互质,表示两个数没有相同的质因子

using namespace std;

typedef long long LL;

const int N = 1000010;

int primes[N], cnt;         //primes存放的是每个素数,cnt是其下标
int phi[N];     //phi表示每个数的欧拉函数
bool st[N];

void get_eulers(int n)
{
    phi[1] = 1;         //1的欧拉函数只有1个
    for (int i = 2; i <= n; i++)
    {
        if (!st[i])
        {
            primes[cnt++] = i;
            phi[i] = i - 1;     //如果i是一个质数的话,从1--i中一共有i-1个数字与i互质,则ph[i]=i-1
        }
        for (int j = 0; primes[j] <= n / i; j++)  //从小到大枚举每个素数
        {
            st[primes[j] * i] = true;
            if (i % primes[j] == 0)     //说明pj是i的质因子
            {
                phi[primes[j] * i] = phi[i] * primes[j];
                break;
            }
            phi[primes[j] * i] = phi[i] * (primes[j] - 1);         //i%primes[j]不为0
        }
    }
}

int main()
{
    int n;
    cin >> n;

    get_eulers(n);

    LL res = 0;
    for (int i = 1; i <= n; i++) res += phi[i];
    printf("%lld\n", res);

    return 0;
}

快速幂

在这里插入图片描述
在这里插入图片描述

#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


LL qmi(int a, int b, int p)               //a^b%p的结果
{
    LL res = 1;             //返回的是res为long long类型
    while (b)                            //本质上求的是b的二进制结果,当b不为0时
    {
        if (b & 1) res = res * a % p;           //b&1就是判断b的二进制表示中第0位上的数是否为1,若为1,b&1=true,反之b&1=false
        a = (LL) a *a % p;              //b&1也可以用来判断奇数和偶数,b&1=true时为奇数,反之b&1=false时为偶数
        b = b >> 1;            //左移1位,相当于除以2
    }      //注意由于res为long long类型,而且上面res=rea*a,res为longlong类型,所以要修改a的值
    return res;
}


int main()
{
    int n;
    scanf("%d", &n);        //输入n的值
    while (n -- )       //n递减
    {
        int a, b, p;
        scanf("%d%d%d", &a, &b, &p);
        printf("%lld\n", qmi(a, b, p));            //注意结果是long long类型
    }

    return 0;
}


快速幂求逆元

在这里插入图片描述


#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


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


int main()
{
    int n;
    scanf("%d", &n);
    while (n -- )
    {
        int a, p;
        scanf("%d%d", &a, &p);
        if (a % p == 0) puts("impossible");
        else printf("%lld\n", qmi(a, p - 2, p));   //这道题主要的思路还是用快速幂
    }

    return 0;
}


扩展的欧几里得算法



#include <iostream>
#include <algorithm>

using namespace std;

int exgcd(int a, int b, int &x, int &y)
{
    if (!b)             //如果b为0,比如 8 0,则最大公约数为8,则x为1,y为0
    {
        x = 1, y = 0;
        return a;       //返回a
    }
    
    //如果b不为0
    int d = exgcd(b, a % b, y, x);          //
    y = y- a / b * x;
    return d;
}

int main()
{
    int n;
    scanf("%d", &n);            

    while (n -- )
    {
        int a, b;
        scanf("%d%d", &a, &b);          //输入a,b
        int x, y;                                      //设置x,y
        exgcd(a, b, x, y);              //传入a,b,x,y
        printf("%d %d\n", x, y);            //直接输出x,y
    }

    return 0;
}


线性同余方程

求一个数x,使a*x/m的余数是b
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述


#include <iostream>
#include <algorithm>

using namespace std;

typedef long long LL;


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


int main()
{
    int n;
    scanf("%d", &n);        //输入n
    
    while (n -- )       //n的值递减
    {
        int a, b, m;            //我们要找到一个x,使得a*x%m==b
        scanf("%d%d%d", &a, &b, &m);

        int x, y;       
        int d = exgcd(a, m, x, y);      //这个d,表示a,m的最大公约数
        if (b % d) puts("impossible");
        else printf("%d\n", (LL)b / d * x % m);  //求余m表示在m的范围内
    }

    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值