NEFU离散数学实验4-数论

相关概念

离散数学中的数论相关概念和公式如下:

1.最大公约数(GCD):两个整数a和b的最大公约数是能够同时整除a和b的最大正整数,记作GCD(a, b)。

2.最小公倍数(LCM):两个整数a和b的最小公倍数是能够同时整除a和b的最小正整数,记作LCM(a, b)。

3.欧几里得算法(Euclidean algorithm):一种求最大公约数的算法,它基于这样一个事实:对于任意两个正整数a和b,有GCD(a,b) = GCD(b,a mod b)(其中mod表示取模运算),而且GCD(a, 0) = a。

4.素数(prime number):一个大于1的正整数,其正因子只有1和它本身,即只能被1和它本身整除。

5.素数定理(Prime number theorem):一个以n为上限的正整数中,素数的个数约为n/ln(n)。

6.费马小定理(Fermat's little theorem):如果p是素数,a是不是p的倍数的整数,则a^(p-1) ≡ 1 (mod p)。

7.欧拉定理(Euler's theorem):如果a和n是正整数且互质,则a^φ(n) ≡ 1 (mod n),其中φ(n)表示小于等于n且和n互质的正整数的个数。

8.欧拉函数(Euler's totient function):φ(n)表示小于等于n且和n互质的正整数的个数,例如φ(10) = 4,因为1, 3, 7, 9都和10互质。

9.扩展欧几里得算法(Extended Euclidean algorithm):一种求解ax + by = GCD(a,b)的一组整数解x和y的算法。

10.中国剩余定理(Chinese remainder theorem):一种求解同余方程组的算法,它可以方便地求解形如x ≡ a1 (mod m1), x ≡ a2 (mod m2),… , x ≡ ak (mod mk)的同余方程组。

11.欧拉降幂定理(Euler's reduced power theorem):如果a和n是正整数且互质,则对于任意的整数b,有a^b ≡ a^(b mod φ(n) + φ(n)) (mod n)。

1. (程序题)同余方程升级版

求关于 x的同余方程 ax≡c(mod b) 的最小正整数解。

Input

一行,包含两个正整数 a,b,c用一个空格隔开。

Output

一个正整数 x ,即最小正整数解。输入数据保证一定有解。

Sample Input

3 10 1

Sample Output

7

下面给出了ex_gcd函数:

void Ex_gcd(int a, int b, int &x, int &y,int &d)

{

    if(b == 0)//递归出口

    {x = 1;y = 0;d=a;return;}

    Ex_gcd(b, a%b, x, y,d);

    int t;

    t=x;

    x =y;

    y = t-(a/b)*y;

}

d: 最大公约数;x是解

#include <iostream> 

using namespace std; 

void Ex_gcd(int a, int b, int &x, int &y, int &d)
{
    // 求最大公约数和扩展欧几里德算法
    if (b == 0) // 如果b等于0,说明a就是最大公约数,同时x=1,y=0
    {
        x = 1;
        y = 0;
        d = a;
        return;
    }
    Ex_gcd(b, a % b, x, y, d); // 递归调用,求解最大公约数和x、y的值
    int t = x; // 保存x的值
    x = y; // 更新x的值为上一次递归中的y
    y = t - (a / b) * y; // 更新y的值为上一次递归中的x减去(a/b)乘以上一次递归中的y
}

int main()
{
    int a, b, c;
    cin >> a >> b >> c; 

    int x, y, d;
    Ex_gcd(a, b, x, y, d); // 求解最大公约数和x、y的值

    int ans = (c / d) * x % (b / d); // 求解方程的解

    if (ans < 0)
        ans += b / d; // 如果ans小于0,加上b/d
   /**
     在求解方程的解时,可能会得到一个负数的解。根据数学的定义,对于模运算,负数的结果应该是在模数 
     的范围内的正数。所以,如果ans小于0,就需要加上b/d,使得ans变为一个在模数范围内的正数。这样 
     可以保证最终得到的解是正确的。

    */
    cout << ans << endl; 

    return 0;
}

2. (程序题)高木同学的因子

今天西片同学又被高木同学捉弄了,高木同学跟西片同学玩了这么一个游戏。两人心中分别想一个数字,这两个数字分别为x和y(1<=x,y<=1e18),然后让西片同学说出一共有多少个整数既是x的因子,又是y的因子。由于西片和高木很有默契,所以保证他们两个想的数x和y的最大公因数不会超过1e9。这个问题又难住了西片同学了,你能帮帮西片同学告诉他答案吗?

Input

单组输入

数据占一行,包含两个整数x和y(1<=x,y<=1e18),保证gcd(x,y)<=1e9。

Output

输出既是x因子又是y因子的整数的个数。输出占一行

Sample Input

12 36

Sample Output

6

Hint

12和36有共同因子1 2 3 4 6 12共计6个数字,所以答案为6

#include <iostream> 
#include <algorithm> 
#include <cmath>

using namespace std; 

typedef long long ll; 

ll gcd(ll a, ll b) {
    // 求最大公约数的函数
    if (b == 0) {
        return a; // 如果b等于0,返回a作为最大公约数
    }
    return gcd(b, a % b); // 递归调用,求解最大公约数
}

int main() {
    ll x, y;
    cin >> x >> y; 

    ll data = gcd(x, y); // 求解x和y的最大公约数
    ll count = 0; // 初始化计数器为0
    for (ll i = 1; i * i <= data; i++) {
        // 从1开始遍历到data,每次增加1
        // 如果i的平方小于等于data,则继续循环
        // 否则跳出循环
        if (data % i == 0) {
            // 如果data能被i整除,说明i和data/i都是data的因数
            // 因此计数器增加2
            count += 2;
        }
    }
    if ((ll)(sqrt(data)) * (ll)(sqrt(data)) == data) {
        // 如果data的平方根的平方等于data,说明data是一个完全平方数
        // 也就是说data有一个因数只出现一次,因此计数器减去1
        count--;
    }

    cout << count << endl; 

    return 0;
}

 3. (程序题)费马小定理

给定3个正整数a,b,c,求a^(b^c) % 1000000007 (10^9 + 7)的值。

Input

多组输入,每组第一行3个数a,b,c,数据范围都在10^9以内。

Output

输出结果。

Sample Input

2 2 3 

5 5 6

Sample Output

256

516190328

---------------------------------------------------------

typedef long long ll;

const int mod=1e9+7;

ll quick_mod(ll a,ll b,ll c)

{

    ll ans=1;

    while(b){

        if(b&1){

            ans=ans*a%c;

            b--;

        }

        b>>=1;

        a=a*a%c;

    }

    return ans;

}

#include <iostream>

using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;

ll quick_mod(ll a, ll b, ll c)
{
    ll ans = 1; // 初始化ans为1,表示初始结果为1
    while (b) // 当指数b不为0时,进行循环
    {
        if (b & 1) // 如果b的最低位为1
        {
            ans = ans * a % c; // 将ans乘以a并取模c,得到新的ans
            b--; // 将b减1
        }
        b >>= 1; // 将b右移1位,相当于将b除以2
        a = a * a % c; // 将a平方并取模c,得到新的a
    }
    return ans; // 返回计算结果ans
}

int main()
{
    ll a, b, c;
    while (cin >> a >> b >> c)
    {
        ll ans = quick_mod(a, quick_mod(b, c, mod - 1), mod);
        cout << ans << endl;
    }
    return 0;
}

上述代码实现了计算a^(b^c) % mod的功能,并结合费马小定理进行了优化。

  • 首先,定义了一个长整型别名ll,用于表示较大的整数。
  • 然后,定义了一个常量mod,表示取模的值,即对10^9 + 7取模。
  • 接着,定义了一个函数quick_mod,用于快速计算幂的结果。
  • 在主函数中,通过循环读入a、b、c的值,并调用quick_mod函数计算a^(b^c) % mod的结果,并输出结果。

费马小定理的优化主要体现在对指数b^c的计算上。根据费马小定理,a^(p-1) ≡ 1 (mod p),其中p为质数。因此,对于指数b^c,可以通过对mod-1取模,将指数缩小到mod-1的范围内,从而加快计算速度。在代码中,调用quick_mod函数时,将b^c对mod-1取模,得到新的指数,然后再计算a的该指数次幂。这样可以避免对较大的指数进行计算,提高了算法的效率。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

烟雨平生9527

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值