阶乘约数——蓝桥杯python组国赛题(C++、唯一分解定理)
题目描述
本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。
定义阶乘 n!=1×2×3×⋅⋅⋅×n。
请问 100!(100 的阶乘)有多少个正约数。
运行限制
最大运行时间:1s
最大运行内存: 128M
分析
这道题是一个唯一分解定理的运用,唯一分解定理通常用来解决大数相除这类型的题,给出唯一分解定理的定义:
任何一个大于1的数,都可以唯一分解成若干个质数的乘积
注意该定理的性质:存在性、唯一性
这是一种数学思维,自行证明起来也容易,想看那种严谨的数学思维推导的证明方法自行去搜索即可。
给出唯一分解定理的算法:
vector<int>v;//存储唯一分解定理的分解值
inline void dev(int n){
int c=sqrt(n);//这里要单独提出来,否则下面for循环的时候n会变
for(int i=2;i<=c;++i)
//当n整除i的时候,就一直除到这个没办法再除为止
while(n%i==0)n/=i,v.push_back(i);
//容易发现,经过这样的处理,绝对不会出来i是非素数的情况下n%i=0,
//比如i=2的时候被n整除,n除i到没有办法再除以之后,n绝对不可能在之后整除4
if(n)//可能整除完还剩下一个数字,这个数字一定是素数
v.push_back(n);
}
放到这道题,我们如果暴搜,基本上是跑不出来的,就算能跑出来,还得要去重,除此之外,数字可能很大,long long也是存不下去的。
这里遇到的问题,就是大数相除问题:通常情况,我们构造出来一个数字num以后需要验证(n!)%num=0,然后这样的数连存储都做不到。
而考虑一种思维,如果这个数能被n!整除,那么我们肯定是被其中的所有数(1、2、…、n)的所有素数因子的若干个组成,而对于100!,我们可以把1到100中的每个数分解质因数,通过这些质因数很容易调配出其约数。
代码如下:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int cnt[105];
inline void dev(int n){
int c=sqrt(n);
for(int i=2;i<=c;++i)
while(n%i==0)n/=i,cnt[i]++;
if(n)cnt[n]++;
}
int main(){
for(int i=2;i<=100;++i)dev(i);
ll ans=1;
for(int i=2;i<=100;++i)ans*=(cnt[i]+1);//+1的原因是某个质因数完全可以不用选,也是一种情况(一个都不选代表的是选1这个非质因数)
cout<<ans<<endl;
}