题目描述
输入n个整数,依次输出每个数的约数的个数
输入描述:
输入的第一行为N,即数组的个数(N<=1000) 接下来的1行包括N个整数,其中每个数的范围为(1<=Num<=1000000000) 当N=0时输入结束。输出描述:
可能有多组输入数据,对于每组输入数据, 输出N行,其中每一行对应上面的一个数的约数的个数。示例1
输入
5 1 3 4 6 12输出
1 2 3 4 6
写题解之前,我想说下。。。我以为这题就是简单的质数个数定理,然后随便整了个程序,算每个数的所有可行的基的指数,然后把各指数加一,再全部乘起来,然后OJ果断把我TLE了。。。。Scheisse!
后来看了别人的代码,自己写了个,先放我写的AC代码,然后进行证明(因为证明这里,我看网上几乎没有)
#define DEBUG1
#include<iostream>
#include<cstdlib>
int main() {
std::ios::sync_with_stdio(false);
int n;
std::cin >> n;
for (int i = 0; i < n; i++) {
int sum = 0;
int num;
std::cin >> num;
int j = 1;
for (; j * j < num; j++) {
if (num % j == 0) {
sum += 2;
#ifdef DEBUG
std::cout << j << " ";
#endif // DEBUG
}
}
if (j == num) {
#ifdef DEBUG
std::cout << j << " ";
#endif // DEBUG
sum++;
}
std::cout << sum << std::endl;
}
#ifdef DEBUG
system("pause");
#endif // DEBUG
return 0;
}
下面进行数学证明:(我不是学数分的。。。证明可能有点。。。你懂的)
算法中,使用了折半算约数,那为什么在折半的时候,能整除就可以直接加2呢?
要证明: x的约数个数等于[1, √x)之间能整除x的个数, (最后再判断√x是否是自然数,来决定最后是否加一)
也就是要证明, 如果 a ∈ [1, √x)且a可以整除x,则必有唯一的b = x/a且b∈[√x, x)之间
证:b=x/a = x/f(x) (这丫是泛函吗?不管了,懂这个意思就行), 1/f(x)是单减函数,b ≥ x/√x = √x,
当b = x时, a = 1,显然b≤x
所以,b∈[√x, x],且由除法的唯一性可知b是唯一的
故,如果在[1, √x]之间有约数a存在,则在[√x, 1]一定有一个b = x/a是x的约数
证毕
结果:我证明了一个很无聊的东西,应该很多人看一下代码就过了吧,我一直没弄懂,直到我把它证明了。。。故写下来,蠢文共批判,疑义相与析