YC263A [ 20240324 CQYC省选模拟赛 T1 ] 光晕 (halation)

题意

给定一个数组 \(a\),每次进行以下操作。

  • 选择一个 \(1 \le x \le n\),将 \(a_x := (a_x - 2 ^ {c_x}) \times 2\),然后 \(c_x := c_x + 1\)

如果通过这个操作使得 \(a\) 严格递增,则 \(a\) 是好的。

你希望找到一个长度为 \(n\) 的好的数组,使得 \(\sum a_i\) 最小,且她的字典序最小。

你需要回答 \(\sum a_i\),同时每次询问 \(a_{b_i}\)

\(n \le 10 ^ 9\)

Sol

这道题看起来非常吓人。

和是好做的。

仔细想想操作,发现一个数 \(x\) 可以操作为 \((x - k) 2 ^ k\)

注意到我们需要使得 \(x\) 最小,考虑 \((x - k)\) 为偶数的情况。

不难发现当前选择 \((x - k) 2 ^ k\) 还不如选择 \((\frac{(x - k)}{2}) 2 ^ {k + 1}\)

通过各种方式:如打表、瞪眼、yy,最终答案数组 (设为 \(a\)) 经过若干次操作后满足递增的数组 (设为 \(a'\)) 满足一段 \(\forall 1 \le i \le A, a'_i = i\)

我们发现这个 \(A\) 就是 \(a'\) 中出现的最大奇数。

这个性质的证明是 trivial 的。

假如当前询问的位置为 \(x\),若 \(x \le A\) 直接输出 \(x\) 按照上述方式得到的最优解即可。

套路地,我们考虑 删去 前面所有的奇数对答案的影响。

删去所有奇数,只会剩下偶数,考虑按照上述方式优化当前所有数字 (也就是所有数除以 \(2\))。

发现这个子问题和原问题几乎一摸一样!

假设我们当前删了 \(y\) 层,得到地答案为 \(x'\),则答案明显为 \(x' \times 2 ^ y\)

虽然层数为 \(\sqrt n\) 的级别,我们依旧无法通过本题。

可以考虑离线下来将所有询问统一处理,这样就只需要枚举一遍层数即可。

也可以考虑将当前每一层删了多少个奇数,以及当前每层可以确定的最大的右端点预处理出来。

复杂度 \(O(\sqrt n)\)

Code


#include <iostream>
#include <algorithm>
#include <cstdio>
#include <array>
#include <vector>
#define int long long
#define pii pair <int, int>
using namespace std;
#ifdef ONLINE_JUDGE

#define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1 << 21, stdin), p1 == p2) ? EOF : *p1++)
char buf[1 << 23], *p1 = buf, *p2 = buf, ubuf[1 << 23], *u = ubuf;

#endif
int read() {
    int p = 0, flg = 1;
    char c = getchar();
    while (c < '0' || c > '9') {
        if (c == '-') flg = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9') {
        p = p * 10 + c - '0';
        c = getchar();
    }
    return p * flg;
}
void write(int x) {
    if (x < 0) {
        x = -x;
        putchar('-');
    }
    if (x > 9) {
        write(x / 10);
    }
    putchar(x % 10 + '0');
}
bool _stmer;

const int N = 2e5 + 5;

#define fi first
#define se second

int calc(int i) { return ((i / 2) * 2 + 2) * (i / 2) / 2 + (i & 1) * (i + 1) / 2; }

array <int, N> s, h, p, ans;

bool _edmer;
signed main() {
    cerr << (&_stmer - &_edmer) / 1024.0 / 1024.0 << "MB\n";
#ifndef cxqghzj
    // freopen("halation.in", "r", stdin);
    // freopen("halation.out", "w", stdout);
#endif
    int n = read(), q = read();
    int pos = 0, sum = 0;
    for (int i = 1; !pos && i <= 2e5; i++) {
        sum += (i + 1) / 2 * i;
        if (calc(i) >= n) pos = i;
    }
    sum -= (calc(pos) - n) * pos;
    int m = pos - 1;
    write(sum), puts("");
    int tot = 0, len = n - calc(m);
    for (int i = 1; i <= pos; i++) h[i] = (pos - i) / 2 + 1;
    for (int i = 1; i <= calc(pos) - n; i++) h[i * 2 - (pos & 1)]--;
    for (int i = 1; i <= pos; i++)
        s[i] = tot + h[i] * 2 - 1, tot += h[i];
    for (int i = 1; i <= pos; i++) h[i] += h[i - 1];
    while (q--) {
        int x = read();
        int tp = lower_bound(s.begin() + 1, s.begin() + pos + 1, x) - s.begin() - 1;
        x -= h[tp];
        while (!(x & 1)) tp++, x >>= 1;
        write(x + tp), puts("");
    }
    return 0;
}
posted @ 2024-03-26 19:19  cxqghzj  阅读(24)  评论(0编辑  收藏  举报