题目描述:
定义函数f(x)表示x的最大奇约数,这里x表示正整数。例如,f(20) = 5,因为20的约数从小到大分别有:1, 2, 4, 5, 10, 20,其中最大的奇约数为5。
给出正整数N,求f(1)+f(2)+…+f(N)
输入格式:
第1行:1个正整数N
输出格式:
第1行:1个正整数,表示题目所求答案
输入样例:
7
输出样例:
21
样例说明:
f(1)+f(2)+f(3)+f(4)+f(5)+f(6)+f(7)=1+1+3+1+5+3+7=21
数据规模:
1<=N<=10^9
解题思路:
一开始我的思路是这样的,就是使用枚举法,把每一个数的最大奇约数都找出来,然后对它们进行求和。但是一旦输入的n超过了几万,就超时了,所以枚举法是行不通的。之后我分析了一下问题,要计算1到n中所有最大奇约数的和,我们可以把问题拆开看,首先要分析一下对于一个数的最大奇约数该如何计算:
如果这个数是奇数,那么最大奇约数就是这个数本身;如果这个数是偶数,这里要想到偶数乘以一个奇数一定是偶数,又因为2是最小的偶数,所以将这个数除以2就能够得到一个偶数或者是一个奇数,如果是奇数,则这个奇数就是这个数的最大公约数;否则,继续除以2,直到得到一个奇数为止。
刚才我们说枚举法是行不通的,所以我们再次分析一下问题:
例如,我输入一个n为奇数6,要计算a(6)=f(1)+f(2)+f(3)+f(4)+f(5)+f(6)的值,刚才我们说奇数的最大奇约数就是他本身,所以这个式子就可以分成两个部分,第一部分:f(1)+f(3)+f(5),它的值就等于1+3+5;第二部分:f(2)+f(4)+f(6),要计算偶数的最大奇约数,就要除以2,所以f(2)+f(4)+f(6)=f(1)+f(2)+f(3)=a(3),即a(6)=1+3+5+a(3);推广到n就为a(n)=(1+n)*(n/2+1)/2+a(n/2);同理,如果n为偶数,则a(n)=(1+n-1)*(n/4)+a(n/2);
参考程序:
#include<iostream>
using namespace std;
long long a(int x)
{
if(x==1)return 1;
else if(x%2==0)return x*x/4+a(x/2);
else return(1+x)*(x/2+1)/2+a(x/2);
}
int main()
{
int n;
cin>>n;
cout<<a(n);
return 0;
}