经典结论 & 前缀和
解法:经典结论 & 前缀和
把 $x$ 变成 $0$ 至少需要 $p$ 步,其中 $p$ 是满足 $4^p > x$ 的最小整数。
知道了每个元素需要的操作步数后,怎么求出答案呢?这就是 leetcode 1953. 你可以工作的最大周数,结论是:设所有元素操作次数之和为 $s$,最大操作次数为 $m$,那么答案为 $\max(\lceil\frac{s}{2}\rceil, m)$。
可以用前缀和的方式把 $[l, r]$ 的操作次数之和算出来,详见参考代码。复杂度 $\mathcal{O}(q\log X)$,其中 $X = 10^9$ 是值域。
参考代码(c++)
class Solution {
public:
long long minOperations(vector<vector<int>>& queries) {
// 计算 [1, x] 的操作次数之和
auto calc = [&](long long x) {
long long ret = 0;
long long p = 1;
// [p, 4p) 范围内的元素,操作次数均为 i
for (int i = 1; p <= x; i++, p *= 4) {
long long cnt = min(p * 4 - 1, x) - p + 1;
ret += cnt * i;
}
return ret;
};
long long ans = 0;
for (auto &qry : queries) {
int l = qry[0], r = qry[1];
ans += max(
// 用前缀和算出 [l, r] 操作次数之和 s,这里求的是 ceil(s / 2)
(calc(r) - calc(l - 1) + 1) / 2,
// 用前缀和算出 r 的操作次数,因为元素越大,操作次数最大
calc(r) - calc(r - 1)
);
}
return ans;
}
};