CodeForces1617D2 Too Many Impostors (hard version)

题目链接

题目大意

  有n个玩家,n是3的倍数,有k个冒名顶替者,保证\(\frac{n}{3} < k < \frac{2n}{3}\),每次可以询问3个玩家中冒名顶替者的数量是否大于一半,最多询问n+6次,问冒名顶替者的数量和编号。

解题思路

  3个一组的询问,因为k的数量限制,必定至少有一组0和一组1,然后我们从两组中各挑两个人,进行四次询问即可找出一个冒名顶替者,一个船员,具体看代码注释。一共消耗\(\frac{n}{3} + 4\)次询问。
  把之前3个一组的询问结果保存下来,如果结果是1,就拿冒名顶替者问12,23两组即可确定3人身份,结果是0类似,具体看代码。一共消耗\(\frac{2n}{3}\)次询问。

代码

const int maxn = 2e5+10;                                                               
const int maxm = 2e6+10;
struct TRP {
    int a[3];
};
TRP t0, t1;
int ask(int a, int b, int c) {
    printf("? %d %d %d\n", a, b, c);
    //cout << endl;
    fflush(stdout);
    int x; scanf("%d", &x);
    return x;
}
vector<TRP> res[2];
int main() { 
    int __; cin >> __;
    while(__--) {
        int n; scanf("%d", &n);
        res[0].clear(), res[1].clear();
        for (int i = 1; i<=n; i+=3) {
            int x = ask(i, i+1, i+2);
            if (x) t1 = {i, i+1, i+2};
            else t0 = {i, i+1, i+2}; 
            res[x].push_back({i, i+1, i+2});
        }
        int f0, f1, res1, res2, cnt = 0;
        cnt += (res1=ask(t0.a[0], t1.a[0], t1.a[1]));
        cnt += (res2=ask(t0.a[1], t1.a[0], t1.a[1]));
        /*
        00 11 - 1 1 0 0
        00 10 - 0 0 0 0
        01 11 - 1 1 1 1
        01 10 - 0 1 1 0
        */
        cnt += ask(t1.a[0], t0.a[0], t0.a[1]);
        cnt += ask(t1.a[1], t0.a[0], t0.a[1]);        
        if (cnt==0) f0 = t0.a[0], f1 = t1.a[2];
        else if (cnt==4) f0 = t0.a[2], f1 = t1.a[0];
        else {
            if (res1+res2==2) f0 = t0.a[0], f1 = t1.a[0];
            else f0 = t0.a[2], f1 = t1.a[2];
        }
        set<int> ans;
        ans.insert(f0);
        for (auto v : res[0]) {
            int x = ask(f1, v.a[0], v.a[1]);
            int y = ask(f1, v.a[1], v.a[2]);
            if (x+y==0) {
                ans.insert(v.a[0]);
                ans.insert(v.a[1]);
                ans.insert(v.a[2]);
            }
            else if (x+y==2) {
                ans.insert(v.a[0]);
                ans.insert(v.a[2]);
            }
            else if (x) {
                ans.insert(v.a[1]);
                ans.insert(v.a[2]);
            }
            else {
                ans.insert(v.a[0]);
                ans.insert(v.a[1]);
            }
        }
        for (auto v : res[1]) {
            int x = ask(f0, v.a[0], v.a[1]);
            int y = ask(f0, v.a[1], v.a[2]);
            if (x+y==2) continue;
            if (x==1) ans.insert(v.a[2]);
            else if (y==1) ans.insert(v.a[0]);
            else ans.insert(v.a[1]);
        }
        printf("! %d", (int)ans.size());
        for (auto v : ans) printf(" %d", v);
        putchar('\n');
        fflush(stdout);
    }
    return 0;   
}
posted @ 2021-12-17 17:16  shuitiangong  阅读(42)  评论(0编辑  收藏  举报