题解:AT_agc015_d [AGC015D] A or...or B Problem
Garbage_fish · · 题解
思路一小时,
oo 不慎开太小,
调题三个钟。
——Garbage_fish 于 2024/11/13 21:41
神秘「找规律」做法。
Part 1 观察 2 的幂
0001
0010 0011
0100 0101 0110 0111
1000
首先假设没有左边界研究一下,观察
0110 0111
1000 1001 1010 1011 ... 1110 1111
10000
但现在有了左边界,假设是
这样子就会漏掉
Part 2 处理左边
这种处理
100100 100101 100110 100111
101000 101001 ... 101100 101101 101110 101111
观察第一行和省略号后面的数,会发现什么?
这是什么原理呢?加
然后你会发现,对
Part 3 处理右边
1000 1001 1010
如上例,询问的区间是
可以把左边界移动到这个加上
011
100 101 110 111
又会发现一个问题,如上例,询问的区间是
然后就没了,实现的时间复杂度瓶颈是
#include <bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
using namespace std;
int l, r;
int lowbit(int x) {
return x & -x;
}
signed main() {
IOS;
cin >> l >> r;
int i = l, ed = 9e18, ans = 0; // 初始 ed 要开 9e18,因为 1e18 < 2 ^ 60。
for (; i <= r;) {
if (i + i - l >= ed) // i 算的东西超过了 ed,已经被算过了。
ans += max(0ll, ed - i);
else // i 能算出哪些数?
ans += i - l + 1;
if (i + lowbit(i) > r) { // 移动左边界,并重新计算 ed。
ed = (i + lowbit(i)) - (i - l);
l = i = i + 1;
} else {
ans += max(0ll, min(r, (i + lowbit(i)) - (i - l) - 1) - i); // 有哪些被漏算了?
i += lowbit(i);
}
}
cout << ans << "\n";
return 0;
}