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
****************************************************************/