[SOJ482]【SPC #2】重要的二元组 ~ Important Pairs

半世苍凉 提交于 2019-12-01 10:20:53

题意简述:给定集合\(\{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;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!