CodeForces - 835E The penguin's game

拿到题面后心里一阵窃喜:这不是很容易就可以二分判断吗?

这里有个坑:当\(y\)在区间内的个数为偶数个时,其实是判断不出来这个区间究竟是全是\(x\)或者有两个\(y\)的。

我们设两个\(y\)的下标为男主与女主。那么首先就是将他们残忍 地拆开!

我们枚举二进制数位(这里是0到9)。每次查询数位为1(即相同)的集合,如果异或答案有\(y\),那么这个数位就属于男主与女主的距离,我们将它记录在\(dif\)中。我们顺便再存一下男主与女主是哪个位不相等,这样就可以拆散他们了。

拆散后,我们就在男主/女主集合里找到那个猪脚光环的人(因为确定当且仅当答案有\(y\)时区间有\(y\))。最后再把\(dif\)异或上去就行了。

算一算次数。第一个循环只需要问10次。第二个循环因为是用二进制位分开,\(siz\)只有\(n\)的一半,只要问9次。所以这是ok哒。

#include<cstdio>
#include<vector>
#include<iostream>
using namespace std;

int n, x, y, dif, bit;
vector <int> q, p;

int read() {
    int x = 0, f = 1; char s;
    while((s = getchar()) > '9' || s < '0') if(s == '-') f = -1;
    while(s >= '0' && s <= '9') {
        x = (x << 1) + (x << 3) + (s ^ 48);
        s = getchar();
    }
    return x * f;
}

int ask() {
    if(q.empty()) return 0;
    printf("? %d", q.size());
    for(int i = 0, siz = q.size(); i < siz; ++ i) printf(" %d", q[i]);
    putchar('\n'); fflush(stdout);
    return read();
}

int main() {
    n = read(), x = read(), y = read();
    for(int i = 0; i <= 9; ++ i) {
        q.clear();
        for(int j = 1; j <= n; ++ j)
            if(j & (1 << i)) q.push_back(j);
        if(q.empty()) break;
        int tmp = ask();
        if(tmp == (x ^ y) || tmp == y) dif ^= (1 << i), bit = i;
    }
    for(int i = 1; i <= n; ++ i)
        if(i & (1 << bit)) q.push_back(i);
        else p.push_back(i);
    if(p.size() > q.size()) swap(p, q);
    int l = 0, r = p.size() - 1;
    while(l < r) {
        int mid = l + r >> 1;
        q.clear();
        for(int i = l; i <= mid; ++ i) q.push_back(p[i]);
        int tmp = ask();
        if(tmp == y || tmp == (x ^ y)) r = mid;
        else l = mid + 1;
    }
    printf("! %d %d\n", min(p[l], p[l] ^ dif), max(p[l], p[l] ^ dif));
    fflush(stdout);
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/AWhiteWall/p/12317114.html