质因数的个数 - 九度教程第54题
题目
时间限制:1 秒 内存限制:32 兆 特殊判题:否
题目描述:
求正整数 N(N>1)的质因数的个数。
相同的质因数需要重复计算。如 120=22235,共有 5 个质因数。
输入:
可能有多组测试数据,每组测试数据的输入是一个正整数 N,(1<N<10^9)。
输出:
对于每组数据,输出 N 的质因数的个数。
样例输入:
120
样例输出:
5
提示:
注意:1 不是 N 的质因数;若 N 为质数,N 是 N 的质因数。
来源:
2007 年清华大学计算机研究生机试真题
对一个数x分解素因数即确定素数p1,p2…pn,使其满足下式:
必要时还要确定e1,e2等幂指数。本题即求e1,e2,…en的和。
利用素数筛法预先筛选出所有可能在题面所给数据范围内成为素因数的素数。并在程序输入待处理数字n时,依次遍历所有小于n的素数,判断其是否为n的因数。若确定某素数为n的因数,则通过试除确定其对应的幂指数。最后求出各个幂指数的和即为所求。
#include <stdio.h>
bool mark[100001];
int prime[100001];
int primeSize;
void init()
{
primeSize=0;
for(int i=2;i<100000;i++){
if(mark[i]==true)continue;
prime[primeSize++]=i;
if(i>=1000)break;
for(int j=i*i;j<=100000;j+=i){
mark[j]=true;
}
}
}
int main()
{
init();
int n;
while(scanf("%d",&n)!=EOF){
int ansPrime[30];//按顺序保存分解出的素因数
int ansSize=0;//分解出素因数的个数
int ansNum[30];//保存分解出的素因数对应的幂指数
for(int i=0;i<primeSize;i++){
//依次测试每一个素数
if(n%prime[i]==0){//若该素数能整除被分解数
ansPrime[ansSize]=prime[i];//则该素数为其素因数
ansNum[ansSize]=0;//初始化幂指数为0
while(n%prime[i]==0){
//从被测试数中将该素数分解出来
//并统计其幂指数
ansNum[ansSize]++;
n/=prime[i];
}
ansSize++;//素因数个数增加
if(n==1)break;//若已被分解成1则分解提前终止
}
}
if(n!=1){
//若测试完2到100000内所有素因数,n仍未被分解至1
//则剩余的因数一定是n一个大于100000的素因数
ansPrime[ansSize]=n;//记录该大素因数
ansNum[ansSize++]=1;//其幂指数只能为1
//此处ansSize++是与n=1的情况保持一致,n记录的是素因数的真实个数
//方便后面统一遍历输出结果
}
int ans=0;
for(int i=0;i<ansSize;i++){
// printf("prime: %d %d\n",ansPrime[i],ansNum[i]);
ans+=ansNum[i];//统计各个素因数的幂指数和
}
printf("%d\n",ans);
}
return 0;
}
该代码按照如下步骤对输入的整数分解素因数:
1.利用素数筛法筛得0到100000区间内所有素数
2.输入n
3.依次测试步骤1中得到的素数能否整除n,若能则表明该素数为它的一个素因数
4.不断将n除以该素数,直到不能再被整除为止,同时统计其幂指数
5.若在完成某个素数的幂指数统计后,n变为1,则表明n的所有素因数全部被分解出来,这样就不用再去遍历后续的素数,分解活动提前终止
6.若遍历,测试,分解完所有预处理出来的素数,n仍旧没被除成1,则表明n存在一个大于100000的因子,且该因子必为其素因子,且其幂指数必然为1
首先说明素数筛法只需筛到100000即可,而不是与输入数据同规模的10 0000 0000.。这样处理的理论依据是:n至多只存在一个大于sqrt(n)的素因数(否则两个大于sqrt(n)的数相乘即大于n)。这样只需将n所有小于sqrt(n)的素数从n中除去,剩余部分必为该大素因数。所以不必依次测试sqrt(n)到n的素数,而是在处理完小于sqrt(n)的素因数时就能确定是否存在该大素因数,若存在其幂指数也必为1.
完成素因数分解后同样可以确定被分解整数因数的个数为(e1+1)(e2+1)…*(en+1),即有所有的素因数不同组合数得出,i(加1是表示不选择该素因数,所以素因数pn有en+1种选择情况)最终结果没有减1是因为算上了因数1.