1948 Problem D 约数的个数

问题 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
****************************************************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值