小易是一个数论爱好者,并且对于一个数的奇数约数十分感兴趣。一天小易遇到这样一个问题: 定义函数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 + 3 + 7 = 21
小易计算这个问题遇到了困难,需要你来设计一个算法帮助他。
输入一个整数N (1 ≤ N ≤ 1000000000)
输出一个整数,即为f(1) + f(2) + f(3).......f(N)
7
21
#include <iostream>
using namespace std;
long long sum(long long N){
if(N==1)return 1;
long long res=0;
if(N%2==0){
res+=N*N/4;
res+=sum(N/2);
}else{
res+=(N+1)*(N+1)/4;
res+=sum((N-1)/2);
}
return res;
}
int main(){
long long N;
while(cin>>N){
cout<<sum(N)<<endl;
}
return 0;
}
#include <stdio.h>
long bigOddSum(long num, long sum) {
if (num == 0) {
return 0;
}
if (num % 2) {
sum += (num / 2 + 1) * (num / 2 + 1);
sum += bigOddSum((num-1)/2, 0);
} else {
sum += (num / 2) * (num / 2);
sum += bigOddSum((num)/2, 0);
}
return sum;
}
int main() {
long num;
long sum = 0;
scanf("%ld", &num);
sum = bigOddSum(num, 0);
printf("%ld\n", sum);
return 0;
}
#include <iostream>
#include <vector>
using namespace std;
int main(){
int N;
while (cin >> N){
long long sum = 0;
/*
* n 为偶数(奇数时情况区别不大)
* f(1) + f(2) + ... + f(N) = f(2) + f(4) + ... + f(N) + f(1) + f(3) + ... + f(N-1)
* f(1) + f(3) + ... + f(N-1) = 1 + 3 + ... + N-1 = (N)*(N)/4;
* f(2) + f(4) + ... + f(N) = f(1) + f(2) + ... + f(N/2); !!! Important here.
*/
while (N){
if((N&0x1)==1){
sum += (long long)(N+1)*(N+1)/4; // 防止溢出
N = (N-1)/2;
}
else{
sum += (long long)(N)*(N)/4;
N = N/2;
}
}
cout << sum << endl;
}
return 0;
}
/*思路是:如果n是偶数,采用折半的方式,如果为奇数,首先将最后一个奇数加到结果中,然后再求前面n-1个偶数的结果*/
#include<iostream>
using namespace std;
int main(){
long n;
while(cin>>n){
long long sum=0;
while(n){
if(n%2==1){//如果是奇数个元素,将最后一个奇数加到结果中
sum+=n;
--n;//然后求前面n-1个偶数的结果
}
else{
sum+=(1+n-1)/2*n/2;//如果是偶数个元素,采用折半的方式,后面n个元素一次为1,3,5,7,。。。n-1
n/=2;
}
}
cout<<sum<<endl;
}
return 0;
}
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner s=new Scanner(System.in);
long num=s.nextInt();
long sum=0;
for(long i=num;i>0;i=i/2){
long temp=(i+1)/2;
sum+=temp*temp;
}
System.out.println(sum);
}
}
总体思路:
因为奇数的最大奇数约数就是自己啊,对于偶数我们只能一直除2直到得到一个奇数即为最大奇数约数
比如1 2 3 4 5 6 7 8 9 10
即n=10 ,此时奇数有1 3 5 7 9 我们把这几个奇数相加然后n/2
得到第二轮序列序列 1 2 3 4 5 分别对应上次的2 4 6 8 10 五个偶数,这是我们再加1 3 5
依次类推
细节问题:
当n为偶数,就有n/2个奇数,根据等差数列求和公式 即((首项+末项)*项数)/2,我们知道n/2个奇数和为((1+n-1)*n/2)/2,
即为(n/2) * (n/2),此时n为偶数,因此 (n/2) * (n/2) = ((n+1)/2) * ((n+1)/2)
当n为奇数,有(n+1)/2个奇数,此时奇数和为((n+1)/2) * ((n+1)/2)
因此两种情况可以用一个等式来总结
//找规律,你会发现基数都是直接取,偶数/2,得到的基础直接取,偶数继续/2,每次循环,可以把规模缩小1/2。
//要注意的是((i + 1) / 2) * ((i + 1) / 2)运算时候,括号的优先级。
#include "iostream"
using namespace std;
typedef long long LL;
int main()
{
LL N;
LL Ans = 0;
while (cin >> N)
{
Ans = 0;
for (LL i = N; i > 0; i = i / 2)
Ans += ((i + 1) / 2) * ((i + 1) / 2);
cout << Ans << endl;
}
return 0;
}
package com.suda.alex;
import java.util.Scanner;
public class Test6 {
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
int n = scanner.nextInt();
System.out.println(sumOfMaxOdd(n));
}
}
/*
* 奇数的最大约数就是本身。问题就是求所有f(i), i为偶数的和 因为要求的是最大奇约数,所以f(2k) = f(k),所以f(2) + f(4)
* + ... + f(2k) = f(1) + f(2) + ... + f(k);
*
* sum(n) = sum (n / 2) + 1 + 3 + ... + n - 1 = sum (n/2) + n*n/4(n 为偶数)
*
* = sum (n - 1) + n (n为奇数)
*
*
*/
public static long sumOfMaxOdd(long n) {
if (n == 1) {
return 1;
}
if (n % 2 == 0) {
return sumOfMaxOdd(n / 2) + n * n / 4;
} else {
return sumOfMaxOdd(n - 1) + n;
}
}
}
#include<iostream>
using namespace std;
/*
总体思路:
因为奇数的最大奇数约数就是自己啊,对于偶数我们只能一直除2直到得到一个奇数即为最大奇数约数
比如1 2 3 4 5 6 7 8 9 10
即n=10 ,此时奇数有1 3 5 7 9 我们把这几个奇数相加然后n/2
得到第二轮序列序列 1 2 3 4 5 分别对应上次的2 4 6 8 10 五个偶数,这是我们再加1 3 5
依次类推
细节问题:
当n为偶数,就有n/2个奇数,根据等差数列求和公式 即((首项+末项)*项数)/2,我们知道n/2个奇数和为((1+n-1)*n/2)/2,
即为(n/2) * (n/2),此时n为偶数,因此 (n/2) * (n/2) = ((n+1)/2) * ((n+1)/2)
当n为奇数,有(n+1)/2个奇数,此时奇数和为((n+1)/2) * ((n+1)/2)
因此两种情况可以用一个等式来总结
*/
//找规律:假设n=16
//while第一次:sum+=1+3+5+7+9+11+13+15(所有奇数的最大奇约数为本身),同时n减半(/2)为8
//while第二次:sum+=1+3+5+7(对应的是16,14,12,10的最大奇公约数),同时n减半为4
//while第三次:sum+=1+3(对应的是8,6的最大奇公约数),同时n减半为2
//while第四次:sum+=1(对应的是4的最大奇公约数),同时n减半为1
//while第五次:sum+=1(对应的是2的最大奇公约数),同时n减半为0
int main()
{
int n;
long long sum = 0;
cin >> n;
while (n)
{
for (int i = 1; i <= n; i += 2)
sum += i;
n /= 2;
}
cout << sum;
system("pause");
return 0;
}
/*常规方法超时
#include<iostream>
using namespace std;
int maxOddDivNum(int num)
{
for (int i = num; i >= 1; i--)
{
if (num % i == 0 && i % 2 != 0)
return i;
}
return 1;
}
int main()
{
int n;
while (cin >> n)
{
int sum = 0;
for (int i = 1; i <= n; i++)
{
sum += maxOddDivNum(i);
}
cout << sum << endl;
}
return 0;
}
*/ ```
# 来个python的递归实现,数据很大要用Decimal处理大数字
# 前提:奇数的最大奇约束就是他自己,偶数的最大奇约束就是一直除以2直到除成奇数
# 分奇数偶数,当n为偶数时,n以下的奇数全部加起来,即n^2/4, 剩下的偶数都除以二就变成
# 了1,2,3,...,n/2这就可以递归了。当n为奇数是也是类似的
from decimal import *
n = int(input())
def digui(n):
if n == 1:
return 1
if n % 2 == 0:
return Decimal(n**2)/Decimal(4) + digui(Decimal(n/2))
else:
return Decimal((n+1)**2)/Decimal(4) + digui(Decimal((n-1)/2))
print(digui(n))
```
#include <iostream>
using namespace std;
int main()
{
long long n;
while(cin>>n){
long long sum = 0;
while(n > 0)
{
if (n%2 == 0)
{
long long temp = n;
while(temp!=1){
temp /= 2;
if(temp%2 == 1)
break;
}
sum += temp;
n = n-1;
}
sum += (n+1)*(n+1)/4;
n /= 2;
}
cout<<sum<<endl;
}
return 0;
}