• 【数论】约数


    一、试除法求n的所有约数

    vector<int> getDivisors(int n) {
    	vector<int> ans;
    	for (int i = 2; i <= n / i; i++) {
    		if (n % i == 0) {
    			ans.push_back(i);
    			if (i != n / i) {
    				ans.push_back(n / i); // n == n/i,只需要存一个
    			}
    		}
    	}
    	return ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    时间复杂度: O ( n ) O(\sqrt n) O(n )

    二、约数个数

    约数和质因子并不是一个意思,但每个约数可以表示成质因子的乘积

    算数基本定理: n = p 1 c 1 ∗ p 2 c 2 ∗ . . . ∗ p k c k n=p_1^{c_1}*p_2^{c_2}*...*p_k^{c_k} n=p1c1p2c2...pkck的约数个数为: ( c 1 + 1 ) ( c 2 + 1 ) … ( c k + 1 ) (c_1+1)(c_2+1)…(c_k+1) (c1+1)(c2+1)(ck+1) p k p_k pk为质因子

    例子: 12 = 2 2 × 3 1 12=2^2×3^1 12=22×31,12的约数有1,2,3,4,6,12共6个,根据公式计算同样是 ( 2 + 1 ) × ( 1 + 1 ) = 6 (2+1)×(1+1)=6 (2+1)×(1+1)=6

    n的每个约数m都可以表示成 m = p 1 b 1 ∗ p 2 b 2 ∗ . . . ∗ p k b k m=p_1^{b_1}*p_2^{b_2}*...*p_k^{b_k} m=p1b1p2b2...pkbk的形式, 0 < = b k < = c k 0<=b_k<=c_k 0<=bk<=ck,每个 b k b_k bk ( c k + 1 ) (c_k+1) (ck+1)种选法,于是就有 ( c 1 + 1 ) ( c 2 + 1 ) … ( c k + 1 ) (c_1+1)(c_2+1)…(c_k+1) (c1+1)(c2+1)(ck+1)个因数

    我们分解质因子后,获取质因子的指数,最后套用 ( c 1 + 1 ) ( c 2 + 1 ) … ( c k + 1 ) (c_1+1)(c_2+1)…(c_k+1) (c1+1)(c2+1)(ck+1)即可

    int getDivisorsNum(int n) {
    	vector<int> nums;
    	for (int i = 2; i <= n / i; i++) {
    		if (n % i == 0) {
    			int num = 0;
    			while (n % i == 0) {
    				n /= i;
    				num++;
    			}
    			// 获取质因子的指数
    			nums.push_back(num);
    		}
    	}
    	if(n > 1) nums.push_back(1);
    	int ans = 1;
    	for (int num : nums) {
    		ans *= (num + 1);
    	}
    	return ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    三、约数之和

    在这里插入图片描述

    例子: 12 = 2 2 × 3 1 12=2^2×3^1 12=22×31,12的约数有1,2,3,4,6,12,约数之和为28,根据公式计算同样是 ( 2 0 + 2 1 + 2 2 ) × ( 3 0 + 3 1 ) = 28 (2^0+2^1+2^2)×(3^0+3^1)=28 (20+21+22)×(30+31)=28

    其中, p 0 + p 1 + p 2 + . . . + p n = ( ( ( p + 1 ) × p + 1 ) × p + 1... ) + 1 p^0+p^1+p^2+...+p^n=(((p+1)×p+1)×p+1...)+1 p0+p1+p2+...+pn=(((p+1)×p+1)×p+1...)+1,一直循环n次

    int getDivisorsSum(int n) {
    	const int mod = 1e9 + 7;
    	unordered_map<int, int> primes;
    	for (int i = 2; i <= n / i; i++) {
    		if (n % i == 0) {
    			while (n % i == 0) {
    				n /= i;
    				primes[i]++;
    			}
    		}
    	}
    	if (n > 1) primes[n] = 1;
    	
    	long long ans = 1;
    	for (auto prime : primes) {
    		int p = prime.first;
    		int n = prime.second;
    		// 计算sum = p^0 + p^1 + p^2 + ... + p^n
    		long long sum = 1;
    		while (n >= 1) {
    			sum = (sum * p + 1) % mod;
    			n--;
    		}
    		ans = ans * sum % mod;
    	}
    	return ans;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    四、最大公约数(欧几里得算法/辗转相除法)

    如果d是a的约数,也是b的约数,则d是ax+by的约数,则有: g c d ( a , b ) = g c d ( b , a % b ) gcd(a,b)=gcd(b,a\%b) gcd(a,b)=gcd(b,a%b) g c d ( a , 0 ) = a gcd(a,0)=a gcd(a,0)=a

    比如a=24,b=18,那么gcd(24,18)=6,gcd(18,24%18)=6

    int gcd(int a, int b) {
    	return b ? gcd(b, a % b) : a;
    }
    
    • 1
    • 2
    • 3

    时间复杂度为 O ( l o g n ) O(logn) O(logn)

  • 相关阅读:
    55、美国德克萨斯大学奥斯汀分校、钱德拉家族电气与计算机工程系:通过迁移学习解决BCI个体差异性[不得不说,看技术还得是老美]
    生信步骤|MAFFT结合HMMER进行多序列比对和基于隐马模型的基因搜索
    Git基本命令和使用
    公务员备考(三十六) 行测 数资强化
    U-App移动统计算力升级!支持跨应用、多事件的打包计算
    企业级logstash简单使用(ELK)
    CesiumJS 下载太慢了
    C++中的类型转换
    SAP:BAPI修改销售订单交货注释
    计算机网络——https
  • 原文地址:https://blog.csdn.net/qq_42500831/article/details/128042217