标签:次数 ++ getchar mat printf mes include putc cst
拿到题面后心里一阵窃喜:这不是很容易就可以二分判断吗?
这里有个坑:当\(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;
}
CodeForces - 835E The penguin's game
标签:次数 ++ getchar mat printf mes include putc cst
原文地址:https://www.cnblogs.com/AWhiteWall/p/12317114.html