CodeForces-835E The penguin's game(思维+二进制乱搞+交互题)

来源:互联网 发布:mysql终端查看数据库 编辑:程序博客网 时间:2024/06/02 02:10

题意:

给出n个数,其中有两个特殊的数值为y,其他不特殊的数值为x,现要求你与评测机交互进行不超过19次询问找出两个特殊值得位置,询问是:你给出该数列的一个任意子集,评测机返回该子集内所有数的异或值。

思路:

贼6的二进制思维题,也是头一回做的交互题。自己想不出来,看的大佬的博客。

由于保证x和y值不同且都不为0,所以每次询问的子集异或值只会有四种取值(x, y, x^y, 0),然后观察发现当该异或值为y或者x^y时,表明该子集中一定只存在一个y。又,因为值为y的两个位置pos1,pos2肯定不同,那么pos1和pos2的二进制形式一定至少存在一位它们俩是不同的,那么我们就根据二进制位确定子集,即从二进制低位到高位每次都选取该位为1的位置组成一个集合进行询问,因为n <= 1000,那么我们最多花费9次(如果前9次都不可行,第10次必定能行)就能将所有数分为两个集合,使每个集合都有且仅有一个y。那么我们再至多通过9次询问不断缩小其中一个集合就能确定出一个y的位置。然而再怎么求第二个位置呢?显然只剩一次询问是无法确定的了,其实我们在前9次询问中寻找pos1和pos2位二进制位不同的时候,通过一个bit来记录两个二进制位是否相同,相同则令bit当前位为0,不同当前位为1(所以我们在前面询问时不管分没分成两个集合都要询问完所有位了,所以最多达到10次)。最后求出ans1,与bit异或一下就是ans2了。


代码:

#include <bits/stdc++.h>using namespace std;int n, x, y, _xor, bit;set<int> s1, s2;set<int>::iterator it;vector<int> vt1, vt2;string str;string chg(int x){string res;while(x) res += x%10+'0', x /= 10;reverse(res.begin(), res.end());return " " + res;}void find(int pos){for(int i = 0; i <= 9; ++i){if(i == pos) continue;str = ""; vt1.clear(), vt2.clear();for(it = s2.begin(); it != s2.end(); ++it)if((*it)&(1<<i)) str += chg(*it), vt1.push_back(*it);else vt2.push_back(*it);if(vt1.empty()) continue;cout << ("?"+chg(vt1.size())+str) << endl;//fflush(stdout);cin >> _xor;if(_xor == (x^y) || _xor == y){for(int j = 0; j < vt2.size(); ++j)s2.erase(vt2[j]);}else{for(int j = 0; j < vt1.size(); ++j)s2.erase(vt1[j]);}}int ans1 = *(s2.begin()), ans2 = 0;ans2 = ans1^bit;if(ans1 > ans2) swap(ans1, ans2);cout << "! " << ans1 << " " << ans2 << endl;}void work(){int pos = -1; bit = 0;for(int i = 0; i <= 9; ++i){str = ""; s1.clear();for(int j = 1; j <= n; ++j)if(j&(1<<i)) str += chg(j), s1.insert(j);if(s1.empty()) continue;cout << ("?"+chg(s1.size())+str) << endl;//fflush(stdout);cin >> _xor;if(_xor == (x^y) || _xor == y){bit += 1<<i;if(s2.empty()) s2 = s1, pos = i;}}find(pos);}int main(){ios::sync_with_stdio(0);cin >> n >> x >> y;work();return 0;}


继续加油~

阅读全文
1 0
原创粉丝点击