约数个数(数论,蓝桥杯)

题目描述:

给定一个数n,再给出n个数,现在要求你求出这些数的乘积的约数个数总和,结果对1e9+7取模。

取值范围:1<n<100; 1<ni<2e9;

分析步骤:

第一:要求约数的个数,我们有许多的求法,比如试除法,线性筛法求。那么本文就将两种方法都讲一遍。题目中说要求出给出的数的乘积的约数个数,如果我们真的去求出了数的乘积总和,那么一定会溢出int函数因为 ni 最大值为2e9只要稍微再乘个数都会超过,所以我们仔细想想,其实我们只需要把每一个数都拆成约数,把他们的约数是哪些分别都统计一下,再结合公式就可以得到最终的答案

第二:试除法求出约数个数。

输入一个n,再用while循环不断地将数输入进去,定义有一个哈希表first代表着具体的约数是哪个;second代表着这个约数有多少。

用for循环不断地去寻找,如果 i 是x的约数的话那么就将mpi++那么约束大小为i的个数就++,再将 x 除去i ,直到 i 不再是x的约数的话,while循环结束。在判断一下最终剩下来的数是不是 1 , 如果不是1的话那么这个数就也是一个约数我们将其存储起来。

定义res为1,运用迭代器向后遍历,利用公式将每一个约数的个数+1的和相乘得到的就是最终的答案。

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
const int N = 1e6+10 , MOD = 1e6+1;

unordered_map<int, int >mp;

int main()
{
    int n ; 
    cin>>n;
    while(n --){
        int x ; 
        cin>>x;
        for(int i = 2 ; i <= x / i ; i++){
            while(x % i == 0){
                mp[i]++;
                x/=i;
            }
        }
     if(x > 1) mp[x]++;
    }
    LL res = 1;
    for(auto t : mp){
        res *= (1+t.second) % MOD;
    }
    cout<<res;
    return 0;
}

但是我们知道其实试除法求出约数个数时间复杂度为根号n,那么当求1~n的所有约数的个数的时候时间复杂度为n根号n那么只要数据量稍微大一点就会超时,所以接下来我们介绍欧拉筛也就是线性筛法将时间复杂度优化为n。

第三:线性筛法求出1~n的约数个数

既然是线性筛法我们就要套用线性筛的模板,

首先明确一下我们的数组分别是有什么用 pN 收集质数, visN判断此数是否遍历过 , aN记录 i 的最小质数出现的次数 ; dN i 数的约数个数;

初始化d1为1,用for循环去遍历,如果这个值是没有被遍历过的那么这个值就一定是质数,我们把他收集进入我们的 p 数组,更新di为2,因为由于该数是个质数那么他的约数就一定只有1 和 他们本身,所以di的约数个数为2,更新ai为1,因为该数是质数所以他最小的质数出现的次数也一定是他本身所以是1。

再用for循环让后面的值一定只被他最小的质因子给除去我们将该点定义为true表示该点不是质数,

进入判断如果:i % pj == 0 。 由于pj一定是它最小的质因子所以这个式子成立的话,就代表着am 比 ai 多了一个质因子所以加1.所以现在的dm和原来的比起来,就只有c1那部分有点差别,所以只要除去原来的部分,再乘上新加的部分就可以得出答案了。

如果判断式子不成立的话则代表这个数是一个新的质因子,因为新的质因子的话那就只有两个约数(1和本身),只有一个质因子(本身),所以我们更新am为1,更新dm则为2*di因为我们看看公式他是要将质因子个数+1的和相乘,所以比原来多了一个质因子套入公式(1+1)== 2 所以是原来的两倍。

cpp 复制代码
void get_d(int n){
     d[1] = 1;
     for(int i = 2 ; i <= n ; i ++){
         if(!vis[i]){
             p[cnt++] = i;
             d[i] = 2;
             a[i] = 1;
         }
         for(int j = 0; p[j] * i <= n ; j ++){
             int m = p[j] * i;
             vis[m] = true;
             if(i % p[j] == 0){
                 a[m] = a[i]+1;
                 d[m] = d[i]/a[m]*(a[m]+1);
                 break;
             }else{
                 d[m] = 2*d[i];
                 a[m] = 1;
             }   
         }
     }
}

线性筛代码:

cpp 复制代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int N = 1e6+10;

int p[N] , vis[N] , cnt;
int a[N] ;
int d[N] ;

void get_d(int n){
     d[1] = 1;
     for(int i = 2 ; i <= n ; i ++){
         if(!vis[i]){
             p[cnt++] = i;
             d[i] = 2;
             a[i] = 1;
         }
         for(int j = 0; p[j] * i <= n ; j ++){
             int m = p[j] * i;
             vis[m] = true;
             if(i % p[j] == 0){
                 a[m] = a[i]+1;
                 d[m] = d[i]/a[m]*(a[m]+1);
                 break;
             }else{
                 d[m] = 2*d[i];
                 a[m] = 1;
             }   
         }
     }
}

int main()
{
    
    int x ; 
    cin>>x;
    get_d(x);
    cout<<d[x]<<endl;
    return 0;
}
相关推荐
青山木13 分钟前
Hot 100 --- 轮转数组
java·数据结构·算法
徐小夕38 分钟前
Loop Engineering 深度解析与实战指南(全网最全)
前端·算法·github
凡人叶枫42 分钟前
Effective C++ 条款22:将成员变量声明为 private
linux·开发语言·c++
北域码匠2 小时前
SHA-1算法:安全哈希原理与应用解析
算法·c#·哈希算法
坚果派·白晓明2 小时前
【鸿蒙PC】SDL3 移植:AtomCode Skills 4 步速通多媒体库适配
c++·华为·ai编程·harmonyos·atomcode·c/c++三方库
手写码匠2 小时前
手写 GraphRAG:从零实现图增强检索增强生成系统
人工智能·深度学习·算法·aigc
BomanGe12 小时前
NSK重载高刚性滚珠丝杠技术详解
经验分享·算法·规格说明书
赴生-3 小时前
C++进阶 C++11(下)
开发语言·c++
有点。3 小时前
C++(贪心算法一)
c++·贪心算法
Matrix_113 小时前
手机里的计算摄影:广角形变校正算法
人工智能·算法·智能手机·计算摄影