CF835E-sol

First Post:

Last Update:

CF835E#

交互题. 给定长度为 的序列 , 恰好有 个数是 , 剩下的 个数是 .

一次询问中你可以查询一个集合 , 交互库会返回 .

试用不超过 次询问求出 使得 .

.

显然一次询问可以求出 的某一位是否完全相同. 具体来说, 假设要求的位是第 位, 那么我们把长度为 的下标序列分成第 位是 的下标序列和第 位是 的下标序列, 然后询问第 位是 的下标序列(假设其长度是 ). 如果该下标序列中:

  • 没有 也没有 : 异或和为 .
  • 既有 也有 : 异或和为 .
  • 只有 其中之一: 异或和为 .

于是一次询问可以判定 的第 位是否相同. 接下来只需求出 其中之一即可. 容易发现我们询问的过程中必然至少有一次会得到第三种结果, 也即可以划分出一个集合, 其中只有 其中之一. 在那个集合上每次随机删去一半的点即可.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include<bits/stdc++.h>
#define f(i,x,y) for(int i=x, i##end=y; i<=i##end; ++i)
#define d(i,x,y) for(int i=y, i##end=x; i>=i##end; --i)
#define uf(i,x,y) for(int i=x, i##end=y; i<i##end; ++i)
#define ll long long
#define pir pair<int, int>
#define fir first
#define sec second
#define mp make_pair
#define pb push_back
char ch;
int rd() {
int f=1, x=0; ch=getchar();
while(!isdigit(ch)) { f=((ch=='-')?-1:f); ch=getchar(); }
while(isdigit(ch)) { x=x*10+ch-'0'; ch=getchar(); }
return x*f;
}
void rd(int& x) { x=rd(); }
using namespace std;
int n; ll x, y, ans[10]; vector<int> Set;
int main() {
cin >> n >> x >> y;
f(i,0,9) {
vector<int> query;
f(j,1,n) if((j>>i)&1) query.pb(j);
if(query.empty()) continue;
cout<<"? "<<query.size()<<" "; for_each(query.begin(), query.end(), [](const int& x){cout << x << ' ';}); cout << endl;
cin >> ans[i]; ll expans = (query.size()&1)*x;
if(ans[i] == expans) ans[i]=0;
else ans[i]=1;
}
f(i,0,9) if(ans[i]) { f(j,1,n) if((j>>i)&1) Set.pb(j); break; }
// for_each(Set.begin(), Set.end(), [](const int& x){cout << x << ' ';}); cout << endl;
while(Set.size()>1) {
vector<int> query, unquery; for(int i=0; i<Set.size(); ++i) if(i<Set.size()/2) query.pb(Set[i]); else unquery.pb(Set[i]);
// cerr << "query.size = " << query.size() << endl;
cout<<"? "<<query.size()<<" "; for_each(query.begin(), query.end(), [](const int& x){cout << x << ' ';}); cout << endl;
ll ans; cin >> ans; ll expans = (query.size()&1)*x;
if(ans == expans) std::swap(unquery, Set);
else std::swap(query, Set);
}
int ans0=Set[0], ans1=Set[0];
f(i,0,9) ans1 ^= (ans[i]*(1<<i));
// cerr <<"ans "; f(i,0,9) cout << ans[i] << " \n"[i==9];
if(ans1<ans0) std::swap(ans0, ans1);
cout << "! " << ans0 << ' ' << ans1 << endl;
return 0;
}