Codeforces Round #427 (Div. 2) E. The penguin's game

本文介绍了一个互动编程挑战,目标是在限定次数内通过提问找到特殊数值的索引位置。利用二进制位操作与集合策略,文章提供了一种高效解决问题的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

E. The penguin’s game
time limit per test1 second
memory limit per test256 megabytes
inputstandard input
outputstandard 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 n, x, y (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 p1 p2

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

有n个数,其中有两个数十独特的,每次可以询问一个集合,要求在19次询问内找出这两个数的下标。
做法:将n个数二进制第i位为0的数放到集合i里面,询问每个集合里面所有数的异或和,最少有一个集合的异或值为y或者y^x,然后二分找到这个点,这样就19次找到了一个点,然后,知道这个点的坐标,那么对于二进制第i为的异或和,如果两个数的二进制相同,那么在这一位上位0,否则为1,已知第一个数,然后可以求出第二个数。

#include<bits/stdc++.h>
using namespace std;

vector<int> G[15];
int cnt[15];
int n,x,y;
bool check(int now){
    if(now == y || now == (x^y)) return true;
    return false;
}
bool judge(int x,int cns){
    cout << '?' << ' ' << x+1;
    fflush(stdout);
    for(int i= 0;i <= x;i ++){
        //cout << ' ' << G[cns][i];
        printf(" %d",G[cns][i]);
        fflush(stdout);
    }
    puts("");
    fflush(stdout);
    int now;
    scanf("%d",&now);
    if(check(now)) return false;
    else return true;
}
int main(){
    cin >> n >> x >> y;
    for(int i= 1;i <= n;i ++){
        for(int j = 0;j < 10;j ++){
            if((i & (1 << j))==0){
                G[j].push_back(i);
            }
        }
    }
    for(int i= 0;i < 10;i ++){
        if(G[i].size() == 0) {
            cnt[i] = 0;
            continue;
        }
        cout <<'?' << ' ' << G[i].size();
        fflush(stdout);
        for(int j = 0;j < G[i].size();j ++){
            printf(" %d",G[i][j]);
            fflush(stdout);
        }
        puts("");
        fflush(stdout);
        cin >> cnt[i];
    }
    int cns = -1;
    for(int i= 0;i < 10;i ++){
        if(check(cnt[i])) cns = i;
    }
    int l = -1,r = G[cns].size()-1;
    while(r - l > 1){
        int mid = (r+l)>>1;
        if(judge(mid,cns)){
            l = mid;
        }
        else r = mid;
    }
    int ans1 = G[cns][r],ans2 = 0;
    for(int i= 0;i < 10;i ++){
        if(check(cnt[i])){
            if((ans1 & (1 << i) )== 0){
                ans2 += 1<<i;
            }
        }
        else{
            if(ans1 &(1<<i)){
                ans2 += 1<<i;
            }
        }
    }
    if(ans1 > ans2){
        swap(ans1,ans2);
    }
    cout << '!' <<  ' ' << ans1 << ' ' << ans2 << endl;
    fflush(stdout);

    return 0;
}/*
? 2 2 4
? 3 1 4 5
? 3 1 2 3
? 5 1 2 3 4 5
? 5 1 2 3 4 5
? 5 1 2 3 4 5
? 5 1 2 3 4 5
? 5 1 2 3 4 5
? 5 1 2 3 4 5
? 5 1 2 3 4 5
6 1 2
3
1




*/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值