题意简述:给定集合\(\{1, 2, \ldots, n\}\),求至少删去几个数后,不存在集合中的\(i, j\)和正整数\(k\),使得\(i+j=2^k\),\(q\)组询问。\(1\leq q\leq 10^6, 1\leq n\leq 10^9\)。
原题条件等价于对任意正整数\(k\)和\(l\),\(2^k+l\)和\(2^k-l\)中至少一个数不存在。
从大到小考虑每个\(k\),显然对于\(2^k\pm l\),优先删除\(2^k-l\)更优。因此我们维护一个值\(\rm{last}\),表示对于当前的\(k\),最大的\(\rm{last}\)个数已经被删除。初始\(\rm{last}=0\),每次操作时分类讨论:
\(\rm{last}\geq 2^k\):被删除的部分已经将\(2^k\)的管辖范围完全覆盖,本次不需删除任何数,\(\rm{last}=\rm{last}-k\)。
\(\rm{last}\leq 2^k\):需要向左删除\(2^k-1-\rm{last}\)个数,\(\rm{last}=2^k-1-\rm{last}\)。
单次询问复杂度\(O(\log n)\)。
#include <bits/stdc++.h> #define R register #define ll long long using namespace std; int t, n; template <class T> inline void read(T &x) { x = 0; char ch = getchar(), w = 0; while (!isdigit(ch)) w = (ch == '-'), ch = getchar(); while (isdigit(ch)) x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar(); x = w ? -x : x; return; } int main() { read(t); while (t--) { read(n); ll val = 1, lst = 0, ans = 0; while (val <= n) val <<= 1; ans = lst = n - (val >> 1); for (R ll i = val >> 2; i; i >>= 1) { ans += max(0ll, i - 1 - lst); lst = max(i - 1 - lst, lst - i); } printf("%lld\n", ans); } return 0; }