题目太难,我想摆了。
这题咋做嘛,人脑搜索呗。
难就难在,如果第一步搜索就走错了,后面的步骤难度就大了。
如果询问单个字符,虽然这样字符集大小变成了 2 2 2,但是这一步花销太大了,以至于难以为继。
于是我们可以通过询问 C H , C O , H C , H O CH,CO,HC,HO CH,CO,HC,HO来代替,这一步花销是 1 1 1。
如果有位置没有被确定,那么要么是 O ? O? O?,要么是两个相同字符。
我们分两种情况讨论。
1.1 1.1 1.1 如果所有位置都是 ? ? ?, 那么打表观察一下,我们发现此时字符集大小为 2 2 2,并且 O O O一定在字符集内。我们可以先询问 O O O OOO OOO,如果成功了就能确定一段前缀,再询问一次整个串长度即可。否则,我们可以再询问 H H H , C C C HHH,CCC HHH,CCC,能够确定出后缀长度。当 n = 4 n=4 n=4时我们还要额外询问一次整个串长度,有最大花费 1 + 1 3 + 1 16 < 1.4 1+\frac{1}{3}+\frac{1}{16}<1.4 1+31+161<1.4 。
1.2 1.2 1.2 如果有位置被确定出来了,考虑找到最右边的位置,比如是 ? ? . . . C H . . . ??...CH... ??...CH...,往后推非常容易,肯定都是 H H H,往前推的话,考虑有些不合法的情况可以被剪掉,因此只需要询问一次就能确定一位的答案,考虑最极端的情况, 1 + ∑ i = 3 50 1 i 2 < 1.4 1+\sum_{i=3}^{50}\frac{1}{i^2}<1.4 1+∑i=350i21<1.4 ,然后就做完了。如果是 ? ? . . . C O . . . ??...CO... ??...CO...呢?那么还是先往前面推,往后推的时候,就只能暴力试了,不过可以考虑先试 O O O,如果这一位还是 ? ? ?就只能是 C , H C,H C,H,那么后面就都可以确定了,因此可以通过。
如何做这种题做得更快一些?升级大脑呗。
#include
#define ll long long
#define pb push_back
#define db double
using namespace std;
int T,n;
string res;
string s[4]={"CH","CO","HC","HO"};
char ch[3]={'C','H','O'};
void ask(string s){
cout<<"?"<<" "<<s<<endl;
int k;cin>>k;
for(int i=1;i<=k;i++){
int x;cin>>x;
for(int j=0;j<s.size();j++)res[x+j]=s[j];
}
}
bool check(char x,char y){
if(x=='C'&&y=='H'||x=='C'&&y=='O'||x=='H'&&y=='C'||x=='H'&&y=='O')return 1;
return 0;
}
string solve(){
for(int i=1;i<=n;i++)res[i]='?';
for(int i=0;i<4;i++)ask(s[i]);
int ok=0;
for(int i=1;i<=n;i++)if(res[i]!='?')ok=1;
if(!ok){
ask("OOO");
int ok2=0;
if(res[1]!='?'){
string tmp,tmp2;
for(int i=1;i<=n;i++){
if(res[i]!='?')tmp+=res[i];
else tmp+='C';
}
ask(tmp);
if(res[n]!='?'){
return tmp;
}
for(int i=1;i<=n;i++){
if(res[i]!='?')tmp2+=res[i];
else tmp2+='H';
}
return tmp2;
}
ask("HHH"),ask("CCC");
if(res[n]!='?'){
string tmp;
for(int i=1;i<=n;i++){
if(res[i]!='?')tmp+=res[i];
else tmp+='O';
}
return tmp;
}
ask("OOCC");
if(res[1]!='?'){
return "OOCC";
}
return "OOHH";
}
int now=0;
for(int i=n;i>=1;i--){
if(res[i]!='?'){
now=i;
break;
}
}
for(int i=now-2;i>=1;i--){
if(res[i]=='?'){
for(int j=0;j<3;j++){
if(res[i]=='?'&&!check(ch[j],res[i+1])){
string tmp;tmp+=ch[j];
for(int k=i+1;k<=now;k++)tmp+=res[k];
ask(tmp);
if(res[i]=='?'){
for(int k=0;k<3;k++){
if(k!=j&&!check(ch[k],res[i+1])){
res[i]=ch[k];
}
}
}
}
}
}
}
while(now<n&&res[now]=='O'){
string tmp;
for(int i=1;i<=now;i++)tmp+=res[i];
ask(tmp+'O');
if(res[now+1]=='?'){
ask(tmp+'C');
}
if(res[now+1]=='?'){
res[now+1]='H';
}
now++;
}
if(now<n){
for(int i=now+1;i<=n;i++)res[i]=res[now];
}
string tmp;
for(int i=1;i<=n;i++){
tmp+=res[i];
}
return tmp;
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>T;
while(T--){
cin>>n;res.clear(),res.resize(n+5);
string o=solve();
cout<<"!"<<" "<<o<<endl;
int ok;cin>>ok;
assert(ok);
}
}