2025.8.27模拟赛

前情提要:本场模拟赛过于超模。

T1

赛时改为了输出最终的 \(a\) 数组。

正着做一遍贪,反着做回来就可以了,复杂度 \(O(n)\)

赛时代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e6 + 5;
int n, m, a[N];
signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> a[i];
    for (int i = 1; i < n; ++i)
        if (a[i] < a[i + 1])
            a[i] = max(a[i], a[i + 1] - m);
        else
            a[i + 1] = max(a[i] - m, a[i + 1]);
    for (int i = n; i > 1; --i)
        if (a[i - 1] < a[i])
            a[i - 1] = max(a[i - 1], a[i] - m);
        else
            a[i] = max(a[i - 1] - m, a[i]);
    for (int i = 1; i <= n; ++i)
        cout << a[i] << ' ';
    cout << '\n';
    return 0;
}

T2

不为 \(1\) 的位置只有 \(\log\) 级别,并且满足这个条件的要求是很严的,所以记忆化搜索即可,细节有点多

爱来自搬题人,以上为题解,讲了和没讲一样,赛时做了几个性质,然后也想到了搜索,但一看就不可写。

T3

唯一有意思的题目了。赛时限制 \(1\) 操作只能做两次,其实是帮助做题了。

首先绝对值这个东西只能确定距离,不能确定方向,所以为了保证方向性,我们将 \(1\) 操作用在数组最小值或最大值上。

一次对于全局的 \(2\) 操作确定 \(maxd=\max a_i- \min a_i\),然后针对前缀二分,即找到最靠前的前缀,使得 \(\max-min=maxd\),这样就找到了最大值或最小值的位置。而另一个值肯定还在前面所以再做一次二分就可以找到另一个值。对另个位置分别做 \(1\) 操作,就可以确定极值及其位置。

然后剩下的数二进制分组,对于每组,做一组不含 \(\max\)的,做一组含 \(\max\) 的,将后者的元素去掉前者的元素,就可以获得这组数与 \(max\) 的差,也就可以获得这组数。由于二进制分组,所以这组数就确定了。

虽然已经很优了,但是我们共进行了 \(1+2+4\log n\) 次操作,大概是 \(35\) 这样,赛时有 90pts,原题限制为 \(30\),依然过不了。

根据信息熵分析。后面的查询已经很优了,前面的二分略显累赘。发现后面的二进制分组查询并不需要知道目前这是最大值还是最小值,反正是个极值就能用。考虑将另一个极值放在分组里一起查了,不用单独去找他。在最后处理的时候另一个极值的位置是确定的,此时再做 \(1\) 操作即可。现在就是 \(1+2+3\log n\) 次操作了,只有 \(27\) 这样。

由于赛题和原题下标上和交互形式有所不同,交原题的代码过于丑陋,就放赛时的了。

赛时代码
#include "C.h"
#include <bits/stdc++.h>
#define eb emplace_back
vector<int> S, ret, ans;
using namespace std;
int ask(int l, int r) {
    S.clear();
    for (int i = l; i <= r; ++i)
        S.eb(i);
    ret = qry2(S);
    int mx = 0;
    for (int v : ret)
        mx = max(v, mx);
    return mx;
}
int id[258], a[258];
multiset<int> st[10][2];
void ins(int x, int y) {
    ret = qry2(S);
    for (int v : ret)
        st[x][y].insert(v);
}
void del(int x) {
    for (int v : st[x][0]) {
        auto it = st[x][1].find(v);
        st[x][1].erase(it);
    }
}
void find(int n, int M1, int M2) {
    int l, r, pmax, pmin = 0, maxn, minn;
    int dlr = ask(0, n - 1);
    l = 0, r = n - 1;
    while (l < r) {
        int mid = l + r >> 1;
        if (ask(0, mid) < dlr)
            l = mid + 1;
        else
            r = mid;
    }
    maxn = qry1(pmax = r);
    for (int i = 0, j = 0; i < n; ++i)
        if (i != pmax)
            id[++j] = i;
    for (int x = 0; (1 << x) <= n - 1; ++x) {
        S.clear();
        for (int i = 1; i <= n - 1; ++i)
            if (i >> x & 1)
                S.eb(id[i]);
        ins(x, 0), S.eb(pmax), ins(x, 1), del(x);
    }
    for (int x = 10; x >= 1; --x) {
        for (int i = 1; i <= n - 1; ++i) {
            if (__builtin_popcount(i) == x) {
                map<int, int> mp;
                mp.clear();
                for (int y = 0; (1 << y) <= n - 1; ++y)
                    if (i >> y & 1)
                        for (int v : st[y][1])
                            ++mp[v];
                for (auto it : mp)
                    if (it.second == x)
                        a[id[i]] = it.first;
                for (int y = 0; (1 << y) <= n - 1; ++y)
                    if (i >> y & 1) {
                        auto it = st[y][1].find(a[id[i]]);
                        st[y][1].erase(it);
                    }
            }
        }
    }
    for (int i = 1; i < n; ++i)
        if (i != pmax && a[i] > a[pmin])
            pmin = i;
    minn = qry1(pmin);
    if (minn < maxn) {
        for (int i = 0; i < n; ++i)
            a[i] = maxn - a[i];
    } else {
        swap(minn, maxn);
        for (int i = 0; i < n; ++i)
            a[i] = minn + a[i];
    }
    for (int i = 0; i < n; ++i)
        ans.eb(a[i]);
    answer(ans);
}

T4

posted @ 2025-08-27 09:37  zzy0618  阅读(8)  评论(0)    收藏  举报