D. Suspicious logarithms Codeforces Round 907 (Div. 2)

Problem - D - Codeforces

The general idea of ​​the question: Let f(X)=log2(x) be rounded down, g(x)=logf(x)x, and there are q times of inquiries, find the sum of g(x) of all numbers in the lr interval.

1<=q<=1e5;4<=l<=r<=1e18

Idea: We make a table and find that within the length of a power of 2, g(x) has at most two different values, and they are all continuously distributed. For example, [4,7] are both 2[8.15] and 8 is 3. There is 2 in [9,15], so we can enumerate each interval whose length is a power of 2. Let the exponent of 2 be i. The current interval [l, r] is [2 raised to the i power, 2 i+1 power -1], we enumerate to find the largest power of i now so that it is less than or equal to l, and at the same time, the value of this power, that is, g(x), is cnt.

There are two situations at this time. The place where g(x)+1 is now*i may be outside the current enumeration interval. The contribution of this interval is (r-l+1)*cnt. The other situation is The place g(x)+1 is in the interval. This place is known to be now*i, so the contribution of this interval is (now*i-1-l+1)*cnt+(r-now*i+1)* (cnt+1), in this way, by enumerating i until the power of i of 2 is greater than the upper limit R, we can get the answer that g(x)x belongs to 1 to R. We let R = the r asked and the l-1 asked, respectively. Just find the subtraction.

#include <bits/stdc++.h>
//#include<__msvc_all_public_headers.hpp>
using namespace std;
const int N = 2e5 + 5;
typedef long long ll;
const ll MOD = 1e9 + 7;
int a[N];
ll cal(ll x)
{
    ll ans = 0;
    for (ll i = 2; (1ll << i) <= x; i++)
    {//枚举2的i次方
        ll l = 1ll << i;//2的i次方
        ll r = min(x, (1ll << i + 1) - 1);//枚举2的i+1次方-1
        ll cnt = 0;//f(l)的z次方
        ll now = 1;//x=l时的z
        while (now <= l / i)
        {//找到最大的小于等于l的i的幂
            cnt++;
            now *= i;
        }
        if (now > r / i)
        {//整个区间g(x)都是一个数
            ans = (ans + (r - l + 1) % MOD * cnt % MOD) % MOD;
        }
        else
        {//前面是一个数,后面是那个数+1
            ans = (ans + (r - now * i + 1) % MOD * (cnt + 1) % MOD + (now * i - l) % MOD * cnt % MOD) % MOD;
        }
    }
    return ans;
}
void solve()
{
    ll l, r;
    cin >> l >> r;
    cout << (cal(r) - cal(l - 1)+MOD) % MOD << '\n';
}
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;
    cin >> t;
    while (t--)
    {
        solve();
    }
    
}

Guess you like

Origin blog.csdn.net/ashbringer233/article/details/134150376