#交互,分类讨论#CF1292E Rin and The Unknown Flower
分析
先尝试锁定一个字母,显然询问 \(CH,CO,CC\) 会比直接询问 \(C\) 更优,虽然牺牲了最后一个位置是否为 \(C\) 的查询。
同理,询问 \(HH,OH,CH\) 会比直接询问 \(H\) 更优,虽然牺牲了第一个位置是否为 \(H\) 的查询。
可以发现这样询问非首尾位置未填的一定是 \(O\),\(C,H\) 一定会被询问出来。
然后首字母只可能填 \(O,H\),尾字母只可能填 \(C,O\),然后再三次判断就可以知道整个串(如果三次判断都不知道,那只能是最后一种情况)
那么操作代价就是 \(\frac{5}{4}+\frac{4-1}{n^2}\),可以发现在 \(n>4\) 时都不超过 \(\frac{7}{5}\),\(n=5\) 时最小,为 \(1.37\)
那么只剩下 \(n=4\) 的情况,显然直接这样问肯定会代价过高。
可以发现只要确定其中两个位置,就可以花不超过 \(\frac{9-1}{16}\) 的代价确定其它位置,
还是尝试锁定 \(C\) 字母,如果锁定得了那么只需要花 \(\frac{3}{4}\) 的代价,
同时其它位置就可以花不超过 \(\frac{6-1}{16}\) 的代价,合起来就是 \(\frac{17}{16}\)
如果 \(C\) 字母不能锁定,再询问 \(OH\),同理,只需要花 \(\frac{4}{4}+\frac{6-1}{16}=\frac{21}{16}\) 的代价。
再询问 \(HH\),如果 \(H\) 被锁定,其实第一二位一定是 \(H\),如果不是那么它在之前一定会被询问出来。
如果第三四位没有被询问出来,那么第三位一定是 \(O\),否则第三位一定被询问出来,
同理只需要确定尾位,需要 \(\frac{5}{4}+\frac{1}{16}=\frac{21}{16}\)。
最后一种情况,中间两位一定是 \(O\),最后询问 \(OOO\),通过 \(\frac{5}{4}+\frac{1}{9}=\frac{49}{36}\) 就可以确定所有位置啦
代码
#include <iostream>
using namespace std;
const char ch[3]={'H','O','C'};
int k,x,Test,n,AC; char S[51];
void doit(char ch,char Ch){
cout<<"? "<<ch<<Ch<<endl;
cin>>k;
for (int i=0;i<k;++i)
cin>>x,S[x]=ch,S[x+1]=Ch;
}
void answ(int t){
bool flag=1;
if (S[1]=='\0'&&S[n]=='\0'){
for (int o=2;o>=t&&flag;--o)
for (int j=0;j<2&&flag;++j)
if (!t||o!=1||j!=1){
S[1]=ch[j],S[n]=ch[o],cout<<"? ";
for (int i=1;i<=n;++i) cout<<S[i]; cout<<endl;
cin>>k;
if (k) cin>>x,flag=0;
}
if (flag) S[1]=S[n]='O',flag=0;
}
for (int i=1;i<n&&flag;++i)
if (S[i]=='\0'&&S[i+1]=='\0'){
for (int o=0;o<3&&flag;++o)
if (!t||o<2||i==n-1)
for (int j=0;j<2&&flag;++j){
S[i]=ch[j],S[i+1]=ch[o],cout<<"? ";
for (int i=1;i<=n;++i) cout<<S[i]; cout<<endl;
cin>>k;
if (k) cin>>x,flag=0;
}
flag=0; break;
}
if (flag){
for (int i=1;i<=n;++i)
if (S[i]=='\0'){
for (int o=0;o<3&&flag;++o) if (!t||o<2||i==n){
S[i]=ch[o],cout<<"? ";
for (int i=1;i<=n;++i) cout<<S[i]; cout<<endl;
cin>>k;
if (k) cin>>x,flag=0;
}
}
}
cout<<"! ";
for (int i=1;i<=n;++i) cout<<S[i];
cout<<endl;
}
int main(){
ios::sync_with_stdio(0);
for (cin>>Test;Test;--Test){
cin>>n;
if (n>4){
for (int i=0;i<3;++i) doit('C',ch[i]);
doit('H','H'),doit('O','H');
for (int i=2;i<n;++i) if (S[i]=='\0') S[i]='O';
answ(1);
}else{
for (int i=0;i<3;++i) doit('C',ch[i]);
if (S[2]!='\0'||S[3]!='\0') answ(0);
else{
doit('O','H');
if (S[2]!='\0'||S[3]!='\0') answ(0);
else{
doit('H','H');
if (S[2]!='\0'){
if (S[4]=='\0'){
if (S[3]=='\0') S[3]='O';
cout<<"? ";
for (int i=1;i<4;++i) cout<<S[i];
cout<<'C'<<endl;
cin>>k;
if (k) cin>>x,S[4]='C';
else S[4]='O';
}
cout<<"! ";
for (int i=1;i<=4;++i) cout<<S[i];
cout<<endl;
}else{
S[2]=S[3]='O';
cout<<"? OOO"<<endl;
cin>>k;
if (k==2) cin>>x,cin>>x,S[1]=S[4]='O';
else if (k==1){
cin>>x,S[x]=S[x+2]='O';
if (S[1]=='\0') S[1]='H';
else S[4]='C';
}else S[1]='H',S[4]='C';
cout<<"! ";
for (int i=1;i<=4;++i) cout<<S[i];
cout<<endl;
}
}
}
}
for (int i=1;i<=n;++i) S[i]='\0';
cin>>AC;
}
return 0;
}