求1到n的所有正整数中,有多少个数的约数个数是奇数

Description

hry在学小学数学的时候就在琢磨一个问题。。1到n的所有正整数中,有多少个数的约数个数是奇数?

Input

第一行有一个正整数T,表示有T组测试数据。 每组测试数据一行一个正整数n.
(1<=T<=10000,1<=n<=1000000000000000000)

Output

每组数据输出一行一个整数,表示1-n中有多少个数有奇数个约数。

Sample Input

5
1
2
3
4
5

Sample Output

1
1
1
2
2

解题思路一:
首先我们把问题分解,第一个问题是求约数个数,第二个是约数个数为奇数,第三个问题为1到n的所有正整数。由此我们可以判断这题的时间复杂度应该接近O(n^(3/2)),即1到n的循环遍历(O(n)),对每个正整数求奇数(O(n^(1/2)))。由此很容易得出下列代码:


C++代码:

#include<iostream>
using namespace std;

int f(long long n)
{
    int sum = 0;
    if (n == 1)
    {
        return 1;
    }
    for (int i = 1; i * i <= n; i++)
    {
        if (n % i == 0)
        {
            if (n / i == i)
            {
                sum++;
            }
            else
            {
                sum += 2;
            }
        }
    }
    return sum;
}

int main()
{
    int T;
    cin >> T;
    while (T > 0)
    {
        long long n;
        cin >> n;
        int count = 0;
        for (long long i = 1; i <= n; i++)
        {
            if (f(i) % 2 != 0)
            {
                count++;
            }
        }
        cout << count << endl;
        T--;
    }
    return 0;
}
/**************************************************************
    Problem: 2581
    Language: C++
    Result: Time Limit Exceed
****************************************************************/

显然这里结果是TLE,说明这个方法有点笨,肯定有比较trick的解法。因此我特地输出了几条数据,有了下面一个发现:


解题思路2:
在经过上面的总结之后,我发现了一个很有趣的规律。当一个数的约数为奇数时,他必为某个数的平方。这是已经有前人总结出来的结论,而我只不过是恰好也发现了这个规律。关于详细证明请参考这篇博客关于完全平方数的因子个数是奇数个的说明
因此这道题就很容易解了,只要计算出有多少个数是某个数的平方,或者说有多少个数开平方结果为正整数。这里我又发现一个小trick:1到n中有多少个数开平方结果为正整数的结果,与对n开平方取整的结果是一致的。所以这道题就可以轻而易举的解决:


C++代码:

#include<iostream>
#include<cmath>
using namespace std;

int main()
{
    int T;
    cin >> T;
    while (T > 0)
    {
        long long n;
        cin >> n;
        int count = 0;
        count = int(sqrt(n));
        cout << count << endl;
        T--;
    }
    return 0;
}
/**************************************************************
    Problem: 2581
    Language: C++
    Result: Accepted
    Time:156 ms
    Memory:1496 kb
****************************************************************/
在C语言,计算从1到一个大数(例如1亿)的所有正整数约数个数通常采用“Sieve of Eratosthenes”(埃拉托斯特尼筛法)这个经典算法。这是一个用于查找素数并确定其所有因子的有效方法。以下是利用这种方法的基本步骤: 1. **初始化数组**:创建一个布尔型数组`isPrime[10000001]`,并将所有元素设为`true`。索引0和1表示它们不是质数,不需要考虑。 2. **筛选素数**:从2开始,遍历数组,将所有2的倍数标记为非素数(即`isPrime[i * 2] = false`)。然后继续找下一个未被标记的数(通常是下一个奇数),直到sqrt(10000000)。对于每个找到的质数,将其倍数也标记为合数。 3. **计数约数**:遍历`isPrime`数组,对每一个素数p,统计小于等于1亿且能被p整除的数的数量,这相当于`count[i/p] += count[i/p*P]`(这里`count`是一个辅助数组,存储着1到当前检查过的最大数的因子个数)。 4. **结果累加**:最后得到的`count[10000000]`就是1到1亿之所有数的约数总和(包括1和本身)。 ```c #include <stdio.h> #include <stdbool.h> #define MAX 10000001 bool isPrime[MAX]; int count[MAX]; void sieveOfEratosthenes() { for (int i = 2; i <= MAX; i++) { if (isPrime[i]) { for (int j = i * i; j <= MAX; j += i) isPrime[j] = false; } } } int countDivisors(int n) { count[1] = 1; for (int i = 2; i * i <= n; ++i) { if (isPrime[i]) { int multiple = i; while (multiple <= n) { count[multiple]++; multiple *= i; } } } return count[n]; } int main() { sieveOfEratosthenes(); printf("Total number of factors for integers from 1 to 10000000: %d\n", countDivisors(10000000)); //
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值