问题 D: 约数的个数
时间限制: 1 Sec 内存限制: 32 MB
献花: 85 解决: 37
[献花][花圈][TK题库]
题目描述
输入n个整数,依次输出每个数的约数的个数。
输入
输入的第一行为N,即数组的个数(N<=1000)
接下来的1行包括N个整数,其中每个数的范围为(1<=Num<=1000000000)
当N=0时输入结束。
输出
可能有多组输入数据,对于每组输入数据,
输出N行,其中每一行对应上面的一个数的约数的个数。
样例输入
6
1 4 6 8 10 12
0
样例输出
1
3
4
4
4
6
思路一:约数个数定理:
约数和定理:
对于一个大于1正整数n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
则由约数个数定理可知n的正约数有(a₁+1)(a₂+1)(a₃+1)…(ak+1)个,
那么n的(a₁+1)(a₂+1)(a₃+1)…(ak+1)个正约数的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
定理证明:
证明:若n可以分解质因数:n=p1^a1*p2^a2*p3^a3*…*pk^ak,
可知p1^a1的约数有:p1^0, p1^1, p1^2……p1^a1
同理可知,pk^ak的约数有:pk^0, pk^1, pk^2……pk^ak ;
实际上n的约数是在p1^a1、p2^a2、…、pk^ak每一个的约数中分别挑一个相乘得来,
可知共有(a₁+1)(a₂+1)(a₃+1)…(ak+1)种挑法,即约数的个数。
由乘法原理可知它们的和为
f(n)=(p1^0+p1^1+p1^2+…p1^a1)(p2^0+p2^1+p2^2+…p2^a2)…(pk^0+pk^1+pk^2+…pk^ak)
注意点:
- Prime数组最好开20以上,否则跑不过
- 使用C语言输入输出,否则超时
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <fstream>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
const int MaxN = 100001;
int Prime[MaxN] , PN = 0 ,FN = 0;
bool Nop[MaxN] = { 0 };
struct Factor
{
int num;
int c;
}Fact[100] = { 0 };
void GetPrimeTable(int n)
{
for (int i = 2; i < MaxN; ++i)
{
if (!Nop[i])
{
Prime[PN++] = i;
if (PN >= n)break;
for (int j = 2 * i; j < MaxN; j += i)//倍数关系,因此直接到2 * i即可
{
if (j % i == 0)
{
Nop[j] = true;
}
}
}
}
}
int main()
{
#ifdef _DEBUG
freopen("data.txt", "r+", stdin);
#endif // _DEBUG
int N;
int Num;
int i,c = 0;
double sqr;
GetPrimeTable(100);
while (EOF != scanf("%d",&N) && N)
{
while (N--)
{
scanf("%d", &Num);
c = 1;
sqr = sqrt(Num);
FN = 0;
memset(Fact, 0, sizeof(Factor) * 100);
for (i = 0; i < PN && Prime[i] <= sqr && Num != 1; ++i)
{
if (Num % Prime[i] == 0)
{
Fact[FN].c = 1;
Fact[FN].num = Prime[i];
Num /= Prime[i];
while (Num % Prime[i] == 0)
{
Num /= Prime[i];
Fact[FN].c += 1;
}
++FN;
}
}
if (Num != 1)
{
Fact[FN].num = Num;
Fact[FN++].c = 1;
}
for (int i = 0; i < FN; ++i)
{
c *= (Fact[i].c + 1);
}
printf("%d\n", c);
}
}
return 0;
}
/**************************************************************
Problem: 1948
User: Sharwen
Language: C++
Result: 升仙
Time:169 ms
Memory:2220 kb
****************************************************************/
思路二:
对半分暴力求因子和:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <cstring>
#include <fstream>
#include <string>
#include <cmath>
#include <algorithm>
#include <queue>
#include <map>
using namespace std;
int GetFactorNum(int n)
{
int res = 0;
for (int i = 1; i * i <= n; ++i)
{
if (n % i == 0)
{
if (n / i != i)
res += 2;
else
++res;
}
}
return res;
}
int main()
{
#ifdef _DEBUG
freopen("data.txt", "r+", stdin);
#endif // _DEBUG
int N, Num;
while (scanf("%d",&N),N)
{
while (N--)
{
scanf("%d", &Num);
printf("%d\n", GetFactorNum(Num));
}
}
return 0;
}
/**************************************************************
Problem: 1948
User: Sharwen
Language: C++
Result: 升仙
Time:309 ms
Memory:1704 kb
****************************************************************/