题目连接:
题目大意:有一个未知的长度为n的字符串$T$,只包含$A,B,X,Y$四个字符且首字母只出现一次,每一次你可以询问一个长度不超过$4n$的字符串$S$,交互库会返回$S$的子串与$T$的前缀的最大公共长度,要求在不超过$n+2$次询问后获得$T$串。
首先首字母只出现一次,我们可以先搞清首字母是什么。
如果一个一个试需要三次,但如果我们二分询问就只需要两次。
具体来说第一次询问$AB$,如果返回$1$则询问$A$,否则询问$X$。
得到首字母之后我们可以想到一个$O(2n)$的做法:
剩下每一位只有三种可能性,我们每次在已知前缀后面加一个字母来试出下一个,每一位需要试两次。
但是可以发现我们并没有用到询问串长度不大于$4n$的条件。
我们假设首字母为$A$,当前已知$T$串的前缀为$s$,那么利用上述条件我们可以用一次询问就得出下一个字母是什么。
因为首字母只会出现一次,所以我们可以将四个长度不超过$n$的询问串连在一起询问,而询问时匹配的$S$的子串一定是四个拼接的询问串中的一个,而不会跨越两个串。
那么我们只需要每次查询$sBsXBsXXsXY$即可,如果返回值为$0$则是$Y$;返回值是$1$则是$B$;返回值是$2$则是$X$。
但要注意最后一位这样询问会超出询问长度限制且返回值无法判断,所以需要特判,这样第一位和最后一位消耗两次,其他位的确定只消耗一次,一共$n+2$次。
#include"combo.h"#includeusing namespace std;string first;string now;string s1,s2,s3;int cnt;int n;std::string guess_sequence(int N){ n=N; first=press("AB")?(press("A")?"A":"B"):(press("X")?"X":"Y"); now=first; first=="A"?s1="B",s2="X",s3="Y":"1"; first=="B"?s1="A",s2="X",s3="Y":"1"; first=="X"?s1="B",s2="A",s3="Y":"1"; first=="Y"?s1="B",s2="X",s3="A":"1"; if(n==1) { return now; } for(int i=2;i