【IOI 2018】Combo / Solution

【IOI 2018】Combo / Solution

Description

官方 PDF 题面

Idea

我们需要一种能一次确定一位的高效询问算法。

考虑到 $p$ 的最大长度为 $4n$,$S$ 的首字母只出现一次,那么我们每次可以基于已知的前缀 $s$,询问 $4$ 种可能的情况。

不妨设 $S$ 的首字母为 $A$,对于已知的前缀 $s$,我们询问

$$sXBsXXsXYsB$$

如果返回值比当前长度大 $2$,说明下一位是 $X$;大 $1$,说明下一位是 $B$,否则下一位为 $Y$。

对开头和结尾的两个字符做二分查找,总询问次数为 $n+2$。

Code

#include "combo.h"
#include <vector>
int head,len=1;
void start();
void end(int N);
std::string c="ABXY",S,id;
std::vector<std::string>h[4]; 
std::string generate_press(){
    return S+id[0]+S+id[1]+id[0]+
    S+id[1]+id[1]+S+id[1]+id[2]; 
}
std::string guess_sequence(int N){
    start();
    while(len<N-1){
        int opt=press(generate_press())-len;
        S+=id[(opt+2)%3];++len;
    }
    if (len==N-1) end(N);
    return S;
}
void start(){
    S=id="";
    if (press("AB")){
        if (press("A")) S+=c[head=0];
        else S+=c[head=1];
    }
    else{
        if (press("X")) S+=c[head=2];
        else S+=c[head=3];
    }
    for (int i=0;i<4;++i)
        if (i!=head) id+=c[i];
}
void end(int N){
    if (press((S+id[0]+S+id[1]))==N){
        if (press((S+id[0]))==N) S+=id[0];
        else S+=id[1];
    }
    else S+=id[2];
}