1. 程式人生 > 其它 >CodeForces1617D2 Too Many Impostors (hard version)

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;   
}