数论-约数

因数,也称为约数(英语:Divisor)是一个常见的数学名词,用于描述自然数 a 和自然数 b 之间存在的整除关系,即 b可以被a 整除。这里我们称 ba 的倍数,ab 的因数或因子。

试除法求约数#

​ 试除法的思路很简单和求质数一样,求一个数n的所有约束,可以枚举从 1n 的所有数,把它记录下来。这里有一个优化,如果 d|n 那么 nd|n ,所以约束也是成对出现的,只要枚举 ndd 之中较小的那个即可。只需要使 d<=nd 即只需要枚举到 d<=n

【问题描述】

给定 n 个正整数 ai,对于每个整数 ai,请你按照从小到大的顺序输出它的所有约数。

【输入格式】

第一行包含整数 n

接下来 i 行,每行包含一个整数 ai

【输出格式】

输出共 n 行,其中第 i 行输出第 i 个整数 ai 的所有约数。

【输入样例】

2

6

8

【输出样例】

1 2 3 6
1 2 4 8

#include<bits/stdc++.h>
using namespace std;

vector<int> div(int n) {
    vector<int> ans;
    
    for (int i = 1; i <= n / i; i ++) {
        if (n % i == 0) {
            ans.push_back(i);
            if (i != n / i) ans.push_back(n / i);  // 注意边界情况,有可能出现 n/i == i的情况导致重复加入数值
        }
    }    
    sort(ans.begin(), ans.end());
    
    return ans;
}


int main()
{
    int n;
    cin >> n;
    while (n --) {
        int x; cin >> x;
        auto ans = div(x);
        for (auto t : ans) cout << t << ' ';
        cout << endl;
    }
    
    
    return 0;
}

约数的个数#

自然数 N 的因数个数以 d(n) 表示。若 N 唯一分解为

N=p1a1×p2a2×p3a3××pnan=i=1npiki,

d(N)=(a1+1)×(a2+1)×(a3+1)××(an+1)=i=1n(ai+1)

例如 2646=2×33×72,则其正因数个数 d(2646)=(1+1)×(3+1)×(2+1)=24

【问题描述】

给定 n 个正整数 ai,请你输出这些数的乘积的约数个数,答案对 109+7 取模。

【输入格式】

第一行包含整数 n

接下来 i 行,每行包含一个整数 ai

【输出格式】

输出一个整数,表示所给正整数的乘积的约数个数,答案对 109+7 取模。

【输入样例】

3

2

6

8

【输出样例】

12

#include<bits/stdc++.h>
using namespace std;

const int mod = 1e9 + 7;
typedef long long ll;
map<int, int> p;

int main()
{
    int n, x;
    cin >> n;
    while (n --) {
        cin >> x;
        for (int i = 2; i <= x / i; i ++) {
            if (x % i == 0) {
                while (x % i == 0) x /= i, p[i] ++;
            }
        }
        if (x > 1) p[x] ++;
    }
    
    ll ans = 1;
    for (auto t : p) ans = ans * (t.second + 1) % mod; // define的时候mod不是整型,是double不能取模,const int mod = 1e9 + 7比较保险。
    cout << ans;
    
    return 0;
}

给定任意一个数n,求其约数的个数。上题相当于求 96 的约数的个数。

约数之和#

自然数 N 的正因数和,以因数函数 σ(N)表示。由质因数分解而得。

N 唯一分解为 N=p1a1×p2a2×p3a3××pnan=i=1npiki, 则 σ(N)=i=1n(j=0aipij)

再由等比级数求和公式可知,上式亦可写成:

σ(N)=p1a1+11p11×p2a2+11p21××pnan+11pn1

例如2646=2×33×72,则其正因数之和

σ(2646)=(1+2)×(1+3+9+27)×(1+7+49)=22121×34131×73171=3×40×57=6840

【问题描述】

给定 n 个正整数 ai,请你输出这些数的乘积的约数之和,答案对 109+7 取模。

【输入格式】

第一行包含整数 n

接下来 i 行,每行包含一个整数 ai

【输出格式】

输出一个整数,表示所给正整数的乘积的约数之和,答案对 109+7 取模。

【输入样例】

3

2

6

8

【输出样例】

252

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int mod = 1e9 + 7;

int main()
{
    int n;
    map<int, int> p;
    cin >> n;
    while (n --) {
        int x; cin >> x;
        for (int i = 2; i <= x / i; i ++) {
            if (x % i == 0) {
                while (x % i == 0) x /= i, p[i] ++;
            }
        }
        if (x > 1) p[x] ++;
    }
    
    ll ans = 1;
    for (auto t : p) {
        int a = t.first, b = t.second;
        ll k = 1;
        while (b --) k = (k * a + 1) % mod;
        ans = ans * k % mod;
    }
    
    cout << ans;
    
    return 0;
}

代码前半部分与之前几乎一样,后半部分很像秦九韶算法,主要是用于计算等比数列和。

例如 1+3+32+33 可以写成 3(3(3+1)+1)+1CPU计算加法比乘法快,可以算的快一点也可以采用快速幂计算等比数列前n项和

最大公约数#

求最大公约数一般采用欧几里得算法,欧几里得算法的核心其实是gcd(a,b)=gcd(b,a mod b)下面进行证明

  1. a mod b进行变换

    a mod b=aab×b=ac×b

  2. 证明对于ab的任意公约数k,都是ba mod b公约数
    b的公约数,同时也是ac×b 的公约数

  3. 证明对于ba mod b的任意公约数m,都是ab的公约数

    即证明ma的公约数,m可以整除a mod b,则m可以整除ac×b所以m可以整除a

综上所述,集合cd(a,b)等于集合cd(b,a mod b),则gcd(a,b)=gcd(b,a mod b),该过程的实现如下

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

顺便一提,最小公倍数的求法lcm(a,b)=a×bgcd(a,b)

int lcm(a, b) {
	return a / gcd(a, b) * b; // 不要写成a*b/gcd(a, b)可能会溢出,先除会让数小一些
}
posted @   Forceco  阅读(1090)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示
主题色彩