Codeforces Round #427 (Div. 2) E. The penguin's game (交互题,二进制分组)

E. The penguin's game

time limit per test: 1 second
memory limit per test: 256 megabytes
input: standard input
output: standard output

Pay attention: this problem is interactive.

Penguin Xoriy came up with a new game recently. He has n icicles numbered from 1 to n. Each icicle has a temperature — an integer from 1 to 109. Exactly two of these icicles are special: their temperature is y, while a temperature of all the others is x ≠ y. You have to find those special icicles. You can choose a non-empty subset of icicles and ask the penguin what is the bitwise exclusive OR (XOR) of the temperatures of the icicles in this subset. Note that you can't ask more than 19 questions.

You are to find the special icicles.

Input

The first line contains three integers nxy (2 ≤ n ≤ 1000, 1 ≤ x, y ≤ 109, x ≠ y) — the number of icicles, the temperature of non-special icicles and the temperature of the special icicles.

Output

To give your answer to the penguin you have to print character "!" (without quotes), then print two integers p1, p2 (p1 < p2) — the indexes of the special icicles in ascending order. Note that "!" and p1 should be separated by a space; the indexes should be separated by a space too. After you gave the answer your program should terminate immediately.

Interaction

To ask a question print character "?" (without quotes), an integer c (1 ≤ c ≤ n), and c distinct integers p1, p2, ..., pc (1 ≤ pi ≤ n) — the indexes of icicles that you want to know about. Note that "?" and c should be separated by a space; the indexes should be separated by a space too.

After you asked the question, read a single integer — the answer.

Note that you can't ask more than 19 questions. If you ask more than 19 questions or at least one incorrect question, your solution will get "Wrong answer".

If at some moment your program reads  - 1 as an answer, it should immediately exit (for example, by calling exit(0)). You will get "Wrong answer" in this case, it means that you asked more than 19 questions, or asked an invalid question. If you ignore this, you can get other verdicts since your program will continue to read from a closed stream.

Your solution will get "Idleness Limit Exceeded", if you don't print anything or forget to flush the output, including for the final answer .

To flush you can use (just after printing):

  • fflush(stdout) in C++;
  • System.out.flush() in Java;
  • stdout.flush() in Python;
  • flush(output) in Pascal;
  • For other languages see the documentation.

Hacking

For hacking use the following format:

n x y pp2

Here 1 ≤ p1 < p2 ≤ n are the indexes of the special icicles.

Contestant programs will not be able to see this input.

Example input

4 2 1
2
1
1

output

? 3 1 2 3
? 1 1
? 1 3
! 1 3

Note

The answer for the first question is .

The answer for the second and the third questions is 1, therefore, special icicles are indexes 1 and 3.

You can read more about bitwise XOR operation here: https://en.wikipedia.org/wiki/Bitwise_operation#XOR.

题意:

交互题,告诉你有 n (n<=1000) 个数(n 个数并不会告诉你),n 个数只含 x , y 两个数字,其中 y 只有两个。

可以对子集发起询问,对于你的每次询问会告诉你你所询问的子集的所有数的异或值,要求在19次询问内找到两个 y 的位置。

如:? 4 1 3 5 7 表示询问的子集包含四个元素{1, 3, 5, 7},则会返回{1, 3, 5, 7}所对应位置上的数字的异或值给你。

总结:

想了很长时间,题解也看了很长时间才有点头绪。

即:首先 n 个数按下标的二进制分成 10 个组(因为 n <= 1000,故 pow(2, 10) = 1024 > n)。

分组规则:对于一个下表 i (1 <= i <= n),可将其分在 i & (1 << bit) != 0 的组内,这样可保证每个数最多被分到 9 组;即对于每个数,它总会在某个集合中缺失。

这样就达到了将要找的两个 y 的分开的效果,可以保证存在这么两个组:分别包含不同的两个 y 。

对每个组可进行预处理,即可询问出两个 y 所在的组,设两个位置分别为 pos1、 pos2,通过预处理可求出 pos1 | pos2。

再对某个仅单独包含一个 y 的集合做二分查找,可求出一个 y 的位置,再通过异或求出另一个 y 的位置。

代码:

#include <bits/stdc++.h>
using namespace std;
int n, x, y;
int pos, pos1, pos2;


int query(vector<int>& a)
{
    int res=0;
    if(a.size()!=0)
    {
        cout<<"? "<<a.size()<<" ";
        for(int i=0; i<a.size(); ++i)
            cout<<a[i]<<" ";
        cout<<endl;
        cin>>res;
    }
    return res;
}

int slove(vector<int>& a)
{
    int l=0, r=(int)a.size()-1;
    while(l < r)
    {
        int m=(l+r)/2;
        vector<int> b;
        for(int i=l; i<=m; ++i)
            b.push_back(a[i]);
        int res=query(b);
        if(res==y || res==(x^y))
            r=m;
        else
            l=m+1;
    }
    return a[l];
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);

    int bit=-1;
    cin>>n>>x>>y;
    for(int i=0; i<=9; ++i)
    {
        vector<int> a;
        for(int j=1; j<=n; ++j)
            if(j & (1<<i))
                a.push_back(j);
        int res=query(a);
        if(res==y || res==(x^y))
        {
            pos |= (1<<i);
            bit=i;
        }
    }

    vector<int> a, b;
    for(int i=1; i<=n; ++i)
    {
        if(i & (1<<bit))
            a.push_back(i);
        else
            b.push_back(i);
    }
    if(a.size() > b.size())
        swap(a, b);
    pos1=slove(a);
    pos2=(pos^pos1);
    if(pos1>pos2)
        swap(pos1, pos2);
    fflush(stdout);
    cout<<"! "<<pos1<<" "<<pos2<<endl;
    return 0;
}

 

转载于:https://www.cnblogs.com/xiepingfu/p/7281972.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值