《算法零基础100讲》(第11讲) 因子数

举报
英雄哪里出来 发表于 2021/11/28 07:53:43 2021/11/28
【摘要】 因子数

零、写在前面

  这是《算法零基础100讲》 专栏打卡学习的第十一讲了,经过一定的磨合,相信大家都已经养成了习惯,那么,激励的话我就不说了,直接来看今天的内容吧。

一、概念定义

  如何求一个数 n n 的因子个数呢?
  朴素的求因子个数的方法为枚举 [ 1 , n ] [1, n] 的数进行余数为 0 判定,复杂度为 O ( n ) O(n) ,这里加入一个小优化,如果 m m n n 的因子,那么必然 n m \frac nm 也为 n n 的因子,不妨设 m n m m \le \frac nm ,则有 m n m \le \sqrt n ,所以只要枚举从 [ 1 , n ] [1, \sqrt n] 的因子然后计数即可,复杂度变为 O ( n ) O(\sqrt n)
  根据 算术基本定理,容易发现, n n 的因子一定是 p 1 p 2 . . . p k p_1、p_2、...、p_k 的组合,并且 p 1 p_1 可以取的个数为 [ 0 , e 1 ] [0, e_1] p 2 p_2 可以取的个数为 [ 0 , e 2 ] [0, e_2] p k p_k 可以取的个数为 [ 0 , e k ] [0, e_k] ,所以根据乘法原理,总的因子个数记为 g ( n ) g(n) ,等于 e i + 1 e_i+1 的连乘,即:

g ( n ) = i = 1 k ( e i + 1 ) g(n) = \prod_{i=1}^{k} (e_i + 1)

  算法时间复杂度即求素因子分解的时间复杂度,为 O ( s ) O(s)

二、题目描述

  给定 x , y ( x , y < 2 31 ) x,y(x, y \lt 2^{31}) ,求 x y x^y 的因子数 m o d p \mod p

三、算法详解

  由于这里的 x y x^y 已经是天文数字,利用上述的枚举法已经无法满足要求,所以我们需要换个思路。考虑到任何整数都能表示成素数的乘积,那么 x y x^y 也不例外,我们首先将 x x 进行因数分解,那么 x y x^y 可以表示成如下形式:

x y = ( p 1 e 1 p 2 e 2 p 3 e 3 . . . p k e k ) y = p 1 y e 1 p 2 y e 2 p 3 y e 3 . . . p k y e k \begin{aligned} x^y &= (p_1^{e_1}p_2^{e_2}p_3^{e_3}...p_k^{e_k}) ^ y \\ &= p_1^{ye_1}p_2^{ye_2}p_3^{ye_3}...p_k^{ye_k} \end{aligned}

  直接套用因子数公式,得到:

g ( x y )   m o d   p = i = 1 k ( y e i + 1 )   m o d   p g(x^y) \ mod \ p = \prod_{i=1}^{k} (ye_i + 1) \ mod \ p

四、源码剖析

  首先准备一个结构体factor,用来表示它的素因子是什么,以及该素因子的个数。

struct factor {
	int prime, count;
	factor() :prime(0), count(0) {}
	factor(int p, int c) : prime(p), count(c) {}
	void print() {
		printf("(%d, %d)\n", prime, count);
	}
};

  然后,利用一个素因子分解的接口Factorization(int n, vector <factor>& ans)来实现枚举素因子的分解。即对于 n = 252 n=252 的情况,函数计算完毕后,ans中存的结果是:[ (2,2), (3,2), (7,1) ]

void Factorization(int n, vector <factor>& ans) {
	ans.clear();
	if(n == 1) {
		return ;                           // (1)
	}
	// 素数试除 
	for(int i = 1; i <= primes[0]; i++) {  // (2)
		if(n % primes[i] == 0) {           // (3)
			factor f(primes[i], 0);        // (4)
			while( !(n % primes[i]) ) {    // (5)
				n /= primes[i];
				f.count ++;            
			}
			ans.push_back(f);              // (6)
		}
		if(n == 1) {
			return ;
		}
	}
	ans.push_back( factor(n, 1) );        // (7)
}
  • ( 1 ) (1) 1 不需要素因子分解。
  • ( 2 ) (2) primes[0]代表在进行素数筛选时,素数的个数,素数筛选的内容,参考:《算法零基础100讲》(第8讲) 素数筛选
  • ( 3 ) (3) 对每一个素数进行试除;
  • ( 4 ) (4) 调用构造函数;
  • ( 5 ) (5) 如果存在prime[i]这个素因子,则将它除掉,并且个数计数自增;
  • ( 6 ) (6) 记录一个素因子信息;
  • ( 7 ) (7) 所有素数都除不尽,说明它本身是一个素数;

五、推荐专栏

💜《夜深人静写算法》💜
三)初等数论入门

六、习题练习

《算法零基础100讲》(第11讲) 因子数

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。