Эта задача эквивалентна нахождению максимума функции f(x)=n%x
в заданном диапазоне.Давайте посмотрим, как эта функция выглядит следующим образом:
Очевидно, что мы могли бы получить максимум раньше, если мы начнем с x=k
, а затем уменьшить x
в то время как это не имеет никакого смысла (до x=max+1
). Также эта диаграмма показывает, что для x
больше, чем sqrt(n)
, нам не нужно уменьшать x
последовательно. Вместо этого мы могли сразу перейти к предыдущему локальному максимуму.
int maxmod(const int n, int k)
{
int max = 0;
while (k > max + 1 && k > 4.0 * std::sqrt(n))
{
max = std::max(max, n % k);
k = std::min(k - 1, 1 + n/(1 + n/k));
}
for (; k > max + 1; --k)
max = std::max(max, n % k);
return max;
}
Волшебное константа 4.0
позволяет повысить производительность за счет уменьшения числа итераций первой (дорогой) петли.
Худшая временная сложность случая может быть оценена как O (min (k, sqrt (n))). Но для достаточно большого k
эта оценка, вероятно, слишком пессимистична: мы могли бы найти максимум намного раньше, и если k
значительно больше sqrt(n)
, нам нужно всего 1 или 2 итерации, чтобы найти его.
Я сделал несколько тестов, чтобы определить, сколько итераций необходимо в худшем случае при различных значениях n
:
n max.iterations (both/loop1/loop2)
10^1..10^2 11 2 11
10^2..10^3 20 3 20
10^3..10^4 42 5 42
10^4..10^5 94 11 94
10^5..10^6 196 23 196
up to 10^7 379 43 379
up to 10^8 722 83 722
up to 10^9 1269 157 1269
темпы роста заметно лучше, чем O (SQRT (п)).
Возможно, существует способ короткого замыкания поиска, начиная с больших значений «k». Я не думаю, что это повлияло бы на большой-о. –
Этот вопрос гораздо более подходит для http://math.stackexchange.com/ IMO. Основная проблема под рукой - алгоритмическая, а не программная. –
@barakmanos. , , Это трудно сказать. ОП знает, как решить проблему, но ищет эффективную реализацию. –