首页 > 编程语言 >【算法专题】约数个数

【算法专题】约数个数

时间:2024-02-05 22:34:54浏览次数:32  
标签:约数 ... 个数 times 算法 num primes

约数个数

约数个数的普通求法

首先我们根据数的唯一分解定理,对 \(N\) 进行分解得:

\[N = p_1^{c_1} \times p_2^{c_2} \times p_3^{c_3} \times ... \times p_k^{c_k} \]

由约数的定义: \(p_1^{c_1}=p_1^{0} \times p_1^{1} \times p_1^{2} \times ... \times p_1^{c_1}\) 共有 \(c_1+1\) 项。

由此类推,那么 \(N\) 的约数个数由乘法原理可求得:

\[(c_1+1)(c_2+1)(c_3+1)...(c_k+1) \]

所以我们在对 \(N\) 分解质因数的时候可以很容易的求出每个 \(p_i\) 的指数,根据公式就可得到 \(N\) 的约数个数。

unordered_map<int, int> mp; // 存储分解后的结果
void devide(int n) // 对n分解质因数
{
	for (int i = 2; i <= n / i; i++) // 分解到根号n就行了
	{
		while (n % i == 0)
		{
			mp[i]++;
			n /= i;
		}
	}
	if (n > 1) mp[n]++;
}
int calc() // 计算约数个数
{
	int sum = 1;
	for (auto t : mp) sum *= (t.second + 1);
	return sum;
}

显而易见,该算法的时间复杂度为 \(O(\sqrt n)\),那么假如我们求 [1,n] 中的所有数的约数个数,那么时间复杂度显而易见的变成了 \(O(n \sqrt n)\)

约数个数的线性求法

在之前的素数筛法中,我们有一个筛法是线性的,就是欧拉筛。那么我们有没有可能在欧拉筛的同时直接求出来每个数的约数的个数呢?这是有可能的。

首先需要准备两个数组:

  • d[i]:表示 \(i\) 的约数个数
  • num[i]:表示 \(i\) 的最小质因子个数,就相当于 \(p_1\) 的指数

有了两个数组了,我们首先分情况讨论:

(一)、\(i\) 为质数:

\[\begin{cases} \ \ \ d[i]=2\\ num[i]=1 \end{cases} \]

  • d[i] :\(i\) 是质数,所以约数只有 \(1\) 和 \(i\) 两个
  • num[i]:\(i\) 是质数,所以最小质因子是 \(i\) ,指数为 \(1\)

(二)、\(primes[j]\) 整除 \(i\):

我们既然是递推求 d[i],那么我们就是要 d[i * primes[j]d[i] 推过来。

首先我们知道:

  • \(primes[j]\) 是 \(i\) 的质因子,那么 \(i*primes[j]\) 唯一分解出来不会产生新的质因子,依旧是 \(p_1,p_2,...,p_k\)
  • \(primes[j]\) 是从小到大枚举的,那么 \(primes[j]\) 是 \(i\) 的最小质因子,所以 \(p_1\) 的指数要加上 \(1\)

\[d[i*primes[j]]=(1+c_1+1)(c_2+1)(c_3+1)...(c_k+1) \]

那么怎么和 \(d[i]\) 关联上,这里就需要用到 \(num[i]\) 了,根据之前的推导 num[i*primes[j]]=num[i]+1 ,因为 \(i*primes[j]\) 这个数只是 \(i\) 的最小质因子的指数多了 \(1\) ,所以我们直接加 \(1\) 即可。

\[d[i] = (num[i]+1)(c_2+1)(c_3+1)...(c_k+1)\\ \\ d[i*primes[j]] = (num[i]+2)(c_2+1)(c_3+1)...(c_k+1)\\ \\ d[i*primes[j]] = d[i] / (num[i]+1) \times (num[i]+2) \]

(三)、\(primes[j]\) 不整除 \(i\):

因为不能整除了,所以 \(i * primes[j]\) 这个数一定多了一个质因子,就是 \(primes[j]\)

\[d[i*primes[j]]=(c_1+1)(c_2+1)(c_3+1)...(c_k+1)(1+1)\\\\ =d[i]\times 2=d[i]\times d[primes[j]] \]

对于 i*primes[j] 这个数的最小质因子,因为我们是从小的质因子开始枚举的,那么 \(primes[j]\) 一定是最小质因子且它的个数只有一个,所以 \(num[i*primes[j]]=1\)

综上,我们可以写出完整代码了!

int primes[N], cnt; // 存质数
bool st[N]; 
int d[N], num[N]; // d:约数个数数组,num:最小质因子个数数组
void init(int n)
{
    for (int i = 2; i <= n; i++)
    {
        if (!st[i]) primes[cnt++] = i, d[i] = 2, num[i] = 1;
        for (int j = 0; primes[j] * i <= n; j++)
        {
            st[i * primes[j]] = true;
            if (i % primes[j] == 0)
            {
                d[i * primes[j]] = d[i] / (num[i] + 1) * (num[i] + 2);
                num[i * primes[j]] = num[i] + 1;
                break;
            }
            else
            {
                d[i * primes[j]] = d[i] * 2;
                num[i * primes[j]] = 1;
            }
        }
    }
}

标签:约数,...,个数,times,算法,num,primes
From: https://www.cnblogs.com/yhgm/p/18008934

相关文章

  • 一套模板搞定二叉树算法题--二叉树算法讲解004
    1、二叉树经典习题模拟忘记知识点和技巧时,遇到一个新的二叉树习题,该如何处理思考和写代码解题?1.1、leetcode965题目和题意:题解1成员变量self.ans:题解2递归回传:1.2、leetcode257该题是个经典二叉树题目题目和题意:题解:分析,所有路径,每一个叶子节点都需要到达。到......
  • 2024牛客寒假算法基础集训营2(小白)
    A.TokitsukazeandBraceletCode:#include<bits/stdc++.h>usingnamespacestd;intmain(){intt;cin>>t;while(t--){inta,b,c,cnt=0;cin>>a>>b>>c;if(a>=150)cnt++;if(a>=200)......
  • 代码随想录算法训练营第十三天|239. 滑动窗口最大值 347.前 K 个高频元素 总结
    239.滑动窗口最大值题目链接:239.滑动窗口最大值-力扣(LeetCode)给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。返回 滑动窗口中的最大值 。思路:首先在不考虑......
  • 【算法专题】筛质数
    筛质数的三种方法什么是质数?只能够被1和它本身整除的数叫做质数1、朴素筛法那么我们从定义出发,假设我们要判断\(n\)是否是质数,我们从\(1\)开始枚举每一个数,一直到\(n\)看看有没有其他的数能够被\(n\)整除,如果没有,那么\(n\)就是质数。假设我们要筛出从\(1\)~......
  • 2024牛客寒假算法基础集训营2
    题目链接A.模拟#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongconstintN=1e5+10;voidsolve(){intn;cin>>n;while(n--){inta,b,c;cin>>a>>b>>c;intans=0;if(a==150)ans+=1......
  • 【教3妹学编程-算法题】1696. 跳跃游戏 VI
    3妹:好冷啊,冻得瑟瑟发抖啦2哥 :没想到都立春了还这么冷啊~3妹:暴雪、冻雨、大雨,这天气还让不让人活啦!!!2哥 :哎,好多人都滞留的高铁站了,没法回家了3妹:我还不知道今天怎么回家呢,惨。2哥:3妹,要不别回去了吧,我们就地过年3妹:切,这里更冷,每天抖啊抖,跳啊跳才能缓解寒冷,我们家那儿可是有暖气......
  • 文心一言 VS 讯飞星火 VS chatgpt (194)-- 算法导论14.3 2题
    二、用go语言,改写INTERVAL-SEARCH的代码,使得当所有区间都是开区间时,它也能正确地工作。文心一言,代码正常运行:在Go语言中,处理开区间(openintervals)时,我们需要特别注意区间的边界条件。开区间不包括其端点,因此在比较时不能使用等于(==)操作符。以下是一个使用Go语言实现的INTERVAL......
  • 【算法】LCT
    参考资料OI-Wiki:LCTFlashHu:LCT总结——概念篇前言第一次学,感觉这玩意挺抽象……只能写下博客巩固一下印象。概念前置知识:树链剖分,Splay给定一棵树,没有任何的更改操作,询问一些有关树上路径问题(如两点之间的权值和),就可以用树上倍增。而如果在此基础上增添了更改某个点......
  • 可控概率抽奖算法
    说明本文PHP语言去实现,只实现核心可控概率引擎,库存判断等其它业务需要其它代码配合实现。代码/***@function封装可控概率的抽奖功能*@param$arrarray数据集合*@param$weight_keystring权重字段*@returnarray被选中的元素*/funct......
  • R语言LASSO特征选择、决策树CART算法和CHAID算法电商网站购物行为预测分析
    全文链接:http://tecdat.cn/?p=32275原文出处:拓端数据部落公众号本文通过分析电子商务平台的用户购物行为,帮助客户构建了一个基于决策树模型的用户购物行为预测分析模型。该模型可以帮助企业预测用户的购物意愿、购物频率及购买金额等重要指标,为企业制定更有针对性的营销策略提供......