定义函数f(x)为x的最大奇数约数,x为正整数,例如f(44) = 11.
现在给出一个N,需要求出f(1) + f(2) + f(3) + … + f(N)
例如: N = 7
f(1) + f(2) + f(3) + f(4) + f(5) + f(6) + f(7) = 1 + 1 + 3 + 1 + 5 + 7 = 21.
分析:
奇数的最大约数是自身, 偶数的最大奇约数是除所有偶因子之后的那个奇数。所以直观的思路就是挨个遍历一遍加起来。
代码如下:
#include <iostream>
using namespace std;
int main(int argc, char **argv)
{
long long N;
long long sum = 0;
long long temp;
cin>>N;
for (long long i = 1; i <= N; ++i)
{
temp = i;
while(0 == temp%2)
temp /= 2;
sum += temp;
}
cout<<sum;
return 0;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
然而, N的取值范围时10^10,所以O(n)的算法是超时的。
考虑优化,设sum(i) = f(1) + f(2) + … + f(i);
求sum(i)的过程中,如果i 为奇数可以直接求,就是 i 本身,即f(i) = i。
问题就是求所有f(i), i为偶数的和。
因为是最大奇约数,所以f(2k) = f(k),所以f(2) + f(4) + … + f(2k) = f(1) + f(2) + … + f(k);
所以
时间复杂度O(logn),可以解决。
代码如下:
#include<iostream>
using namespace std;
long long sum(long long n) {
if (n == 1) {
return 1;
}
if (n % 2 == 0) {
return sum(n / 2) + n * n / 4;
}
else {
return sum(n - 1) + n;
}
}
int main() {
int N;
cin >> N;
cout << sum(N) << endl;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
另外
用表示自然数的所有因数中最大的那个奇数,例如:9的因数有1,3,9,,10的因数有1,2,5,10,那么