#交互,分类讨论#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;
} 
posted @ 2022-03-27 16:44  lemondinosaur  阅读(36)  评论(0编辑  收藏  举报