WC2019 I 君的商店

时间:2022-09-14 18:41:43

交互题

一个 01 序列,告诉你其中 1 有奇数个还是偶数个,每次可以给定两个集合 $A$,$B$,系统会告诉你 $A \leq B$ 或者 $B \leq A$

求序列

 

交互次数要求 $5n + O(log_2 n)$

有一个 subtask 满足原序列是一条从不上升或者不下降的链,要求 $O(log_2n)$

 

sol:

首先有一个交互次数 $2n + 5n$ 的做法:首先 $2n$ 次找出最大值,最大的那个肯定是 $1$,之后每次问两个还不确定的($a,b$),$a+b$ 是否大于等于 $1$

如果大于等于,那么 $a,b$ 中较大的是 $1$,否则 $a,b$ 中较小的是 $0$。最后特判一下奇偶性不符的情况即可

 

然后对于一条链的情况,首先,两个端点一定有一个 1,二分找出一个位置最小的 $x$ 使得 $p[x] + p[x+1] \geq 1$ 即可

分界线那里用奇偶性特判一下 $O(log_2n)$

 

正解

发现 5n 的部分不太好优化,考虑一边 5n 一边确定一个递增的关系,然后用 logn 次确定那条链

具体地,可以从三个数 $(x,y,z)$ 开始,先比较 $x,y$,不妨设大的那个是 $y$

如果 $x+y \leq z$,则 $x=0$,再找一个 $x$

否则 $y \geq z$,把 $y$ 放到 $z$ 的位置,再找一个 $y$

这样会确定若干个 $0$ ,剩一个比不出去的,和一条递增的链

容易知道比不出去的和链最大值中较大的那个是 $1$,可以直接上二分

二分之后还有一个不确定的分界线和一个比不出去的,$O(1)$ 讨论一下即可

WC2019 I 君的商店WC2019 I 君的商店
#include <bits/stdc++.h>
#include "shop.h"
#define LL long long
#define rep(i, s, t) for (register int i = s, i##end = t; i <= i##end; ++i)
#define dwn(i, s, t) for (register int i = s, i##end = t; i >= i##end; --i)
using namespace std;
int arr[5], brr[5];
int ans[100010], que[100010], chain[100010];
int ask(int x, int y) {
    arr[0] = x, brr[0] = y;
    return query(arr, 1, brr, 1);
}
int ask2(int x, int fst, int scd) {
    arr[0] = x, brr[0] = fst, brr[1] = scd;
    return query(arr, 1, brr, 2);
}
void find_price(int task_id, int N, int K, int ans[]) {
    auto solvechain = [&](int N, int K) {
        int l = 0, r = N - 2, res = N - 1;
        while (l <= r) {
            int mid = (l + r) >> 1;
            if (ask2(que[N - 1], que[mid], que[mid + 1]))
                res = mid, r = mid - 1;
            else
                l = mid + 1;
        }
        int val = res;
        if (K != ((N - res) & 1))
            res++;
        rep(i, 0, res - 1) ans[que[i]] = 0;
        rep(i, res, N - 1) ans[que[i]] = 1;
        return val;
    };
    for (int i = 0; i < N; ++i) ans[i] = 0;
    if (task_id == 3) {
        for (int i = 0; i < N; ++i) que[i] = i;
        if (ask(N - 1, 0))
            reverse(que, que + N);
        solvechain(N, K);
    } else if (task_id == 6) {
        if (N == 1)
            ans[0] = 1;
        else if (N == 2) {
            int mx = ask(0, 1) ? 1 : 0;
            ans[mx] = 1;
            if (!K)
                ans[!mx] = 1;
        } else {
            int dfn = N - 1, cd = 1;
            chain[0] = 0;
            for (int i = 1; i < N; ++i) que[i] = i;
            while (dfn > 1) {
                if (!ask2(chain[cd - 1], que[dfn], que[dfn - 1])) {
                    if (!ask(que[dfn], que[dfn - 1]))
                        swap(que[dfn], que[dfn - 1]);
                    ans[que[dfn]] = 0;
                } else {
                    if (ask(que[dfn], que[dfn - 1]))
                        swap(que[dfn], que[dfn - 1]);
                    chain[cd++] = que[dfn];
                }
                dfn--;
            }
            if (ask(que[dfn], chain[cd - 1])) {
                ans[chain[cd - 1]] = 1;
                int cmx = que[dfn];
                dfn = cd;
                for (int i = 0; i < cd; ++i) que[i] = chain[i];
                int cur = solvechain(dfn, K);
                K ^= ((dfn - cur - 1) & 1);
                cur = que[cur];
                if (!ask2(chain[cd - 1], cmx, cur)) {
                    if (ask(cmx, cur))
                        ans[cmx] = 0;
                    else
                        ans[cur] = 0;
                } else {
                    if (ask(cur, cmx))
                        ans[cmx] = 1;
                    else
                        ans[cur] = 1;
                    K ^= 1;
                }
                ans[cmx] = K;
            } else {
                ans[que[dfn]] = 1;
                chain[cd++] = que[dfn];
                for (int i = 0; i < cd; ++i) que[i] = chain[i];
                solvechain(cd, K);
            }
        }
    } else {
        int mx = 0;
        for (int i = 1; i < N; ++i)
            if (ask(mx, i) == 1)
                mx = i;
        ans[mx] = 1;
        int dfn = 0;
        K ^= 1;
        for (int i = 0; i < N; ++i) {
            if (i == mx)
                continue;
            que[++dfn] = i;
        }
        while (dfn > 1) {
            if (ask2(mx, que[dfn], que[dfn - 1]) == 0) {
                if (ask(que[dfn - 1], que[dfn]))
                    swap(que[dfn - 1], que[dfn]);
                ans[que[dfn]] = 0;
            } else {
                if (!ask(que[dfn - 1], que[dfn]))
                    swap(que[dfn - 1], que[dfn]);
                ans[que[dfn]] = 1;
                K ^= 1;
            }
            dfn--;
        }
        if (K && dfn)
            ans[que[dfn]] = 1;
    }
}
View Code