【问题标题】:Find the sum of the greatest odd divisor of all integers 1 through N求所有整数 1 到 N 的最大奇数之和
【发布时间】:2020-10-02 22:42:45
【问题描述】:

给定一个正整数N。f(N)是N的最大奇数。

求和(f(1)+f(2)+f(3)+....f(N))%m。

如果 N 是 10^18 并且 m 可以达到 10^9,那么更快的算法应该是什么?

暴力破解算法示例:

int sum=0;
int a[n+1];
for(int i=1;i<=n;i++){
    if(i%2!=0)
        a[i] = i;
    else
        a[i] = a[i/2];
}
for(int i=1;i<=n;i++){
    sum+=a[i];
}
cout<<sum;

【问题讨论】:

  • 这不是 C++ 问题。
  • 在编码中,可以使用哪种方法?
  • 什么是 f(3)?是 3 吗?
  • @sukesh 您可以选择任何语言。它可以是 C、C++、Python、Java 等。算法不依赖于特定的语言。
  • 我正在使用蛮力方法

标签: c++ algorithm math


【解决方案1】:

[1,N]范围内奇数的和是奇数个数的平方,即((N+1)/2)^2,其中'/'表示整数除法。我们称之为 p(N)。

我们仍然需要找到 [1,N] 范围内偶数的最大奇数除数之和。我们可以将范围内的偶数除以 2 的最大幂。

For 1 power of 2: p(N/2)
For 2 powers of 2: p(N/4)
For 3 powers of 2: p(N/8)

等等……

即,f(N) = p(N) + p(N/2) + p(N/4) + p(N/8) + ...

以下是 N = 1、2、...、20 的结果:

N,  f(N)
1,    1
2,    2
3,    5
4,    6
5,   11
6,   14
7,   21
8,   22
9,   31
10,  36
11,  47
12,  50
13,  63
14,  70
15,  85
16,  86
17, 103
18, 112
19, 131
20, 136

【讨论】:

  • 华丽!自从这个问题引起了我的兴趣以来,我昨晚越来越接近这个问题,但并没有完全到达那里。这做到了。太棒了!
【解决方案2】:

无耻地采用戴夫的解决方案,但添加代码。

查找:

F(N) mod M = (f(1) + f(2) + ... + f(N)) mod M

给定:

1.  f(n) = greatest odd divisor of n
1a. f(n) = n, for all odd n
1b. f(n) = f(n/2), for all even n
    (note, this is recursive: f(n) = f(n/2) = f(n/4) = ... until we hit an odd number)
2.  p(n) = sum of all odd numbers less than or equal to n
2a. p(n) = (number of odd numbers less than or equal to n) squared
3.  F(N) = f(1) + f(2) + ... + f(N)
4.  1 <= N <= 10^18
5.  1 <= M <= 10^9

然后:

F(N) = p(N) + [f(2) + f(4) + ... + f(largest even not > N)]
     = p(N) + [f(1) + f(2) + ... + f(N/2)]
     = p(N) + F(N/2)
     = p(N) + p(N/2) + p(N/4) + ...

and 

F(N) mod M = (p(N) mod M + p(N/2) mod M + ...) mod M

p(N) 的复杂度为 O(1),而递归的 F(N) 的复杂度为 O(log N),这将比暴力方法(可能是 O(N log N))快得多(我相信。有人可以验证这一点)。

下面的 C++ 代码完成了这个算法

#include <iostream>

using value_type = unsigned long long;

value_type p_N_mod_M(value_type N, value_type M)
{
    // nom := _N_umber of _O_dd numbers not greater than N, _M_od-M
    value_type nom = ((N + 1) / 2) % M;
    return (nom * nom) % M;
}

value_type F_N_mod_M(value_type N, value_type M)
{
    if (N == 0) return 0;
    if (N == 1) return 1;

    return (p_N_mod_M(N, M) + F_N_mod_M(N / 2, M)) % M;
}

int main()
{
    value_type N, M;
    std::cout << "Calculates F(N) mod M = (f(1) + f(2) + ... + f(N)) mod M,\n"
        "where f(n) is the greatest odd divisor of n.\n"
        " [1 <= N <= 10^18]; [1 <= M <= 10^9]\n"
        "------------------------------------------------------------------\n"
        "Enter N followed by M: ";
    std::cin >> N >> M;

    std::cout << "\nF(" << N << ") mod " << M << " = " << F_N_mod_M(N, M) << "\n";
}

样本输出:

Calculates F(N) mod M = (f(1) + f(2) + ... + f(N)) mod M,
where f(n) is the greatest odd divisor of n.
 [1 <= N <= 10^18]; [1 <= M <= 10^9]
------------------------------------------------------------------
Enter N followed by M: 20 200

F(20) mod 200 = 136

----

Calculates F(N) mod M = (f(1) + f(2) + ... + f(N)) mod M,
where f(n) is the greatest odd divisor of n.
 [1 <= N <= 10^18]; [1 <= M <= 10^9]
------------------------------------------------------------------
Enter N followed by M: 20 135

F(20) mod 135 = 1

【讨论】:

    猜你喜欢
    • 2021-08-14
    • 2016-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-17
    • 1970-01-01
    相关资源
    最近更新 更多