无耻地采用戴夫的解决方案,但添加代码。
查找:
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