Ну, это не , что сложно ...
Функция с одним аргументом solve(int a)
является ключом.Он короткий, поэтому я вырезал и вставлял его здесь:
long long solve(int a)
{
if(a == 0) return 0 ;
if(a % 2 == 0) return solve(a - 1) + __builtin_popcount(a) ;
return ((long long)a + 1) / 2 + 2 * solve(a / 2) ;
}
Он работает только для неотрицательных значений a и подсчитывает число 1 бит во всех целых числах от 0 до a
включительно.
Функция имеет три случая:
a == 0
-> возвращает 0. Очевидно.
a
even -> возвращает число 1 бит в a
plus solve(a-1)
.Также довольно очевидно.
Последний случай интересный.Итак, как мы посчитаем число 1 бит от 0 до нечетного числа a
?
Рассмотрим все целые числа от 0 до a
и разделим их на две группы: четные ишансы.Например, если a
равно 5, у вас есть две группы (в двоичном формате):
000 (aka. 0)
010 (aka. 2)
100 (aka. 4)
и
001 (aka 1)
011 (aka 3)
101 (aka 5)
Обратите внимание, что эти две группы должны иметь одинаковый размер (посколькуa
нечетно и диапазон включительно).Чтобы подсчитать, сколько 1 битов имеется в каждой группе, сначала подсчитайте все биты, кроме последних, а затем подсчитайте последние биты.
Все биты, кроме последних, выглядят так:... и это выглядит так для обеих групп.Число 1 бит здесь просто solve(a/2)
.(В этом примере это число 1 битов от 0 до 2. Также напомним, что целочисленное деление в раундах C / C ++ вниз .)
Последний бит равен нулю для каждогочисло в первой группе и по одному на каждое число во второй группе, поэтому эти последние биты вносят (a+1)/2
один бит в общую сумму.
Таким образом, третий случай рекурсии - (a+1)/2 + 2*solve(a/2)
с соответствующими приведениямиlong long
для обработки случая, когда a
равно INT_MAX
(и, таким образом, a+1
переполняется).
Это решение O (log N).Чтобы обобщить его до solve(a,b)
, вы просто вычисляете solve(b) - solve(a)
плюс соответствующую логику для беспокойства об отрицательных числах.Вот что делает два аргумента solve(int a, int b)
.