题解:[AGC044D] Guess the Password

前言

比较可做的交互题,瓶颈在于编辑距离的转化。

思路分析

首先考虑编辑距离是困难的,考虑弱化条件。

因为本题要求确定一个字符串,因此,可以尝试将编辑距离转化为判定子序列相关的信息。

具体地,考虑,对于两个字符串 \(S,T\)\(S\)\(T\) 的子序列当且仅当 \(f(S,T)=|S|\)

所以我们可以用编辑距离来判定子序列。

这样,我们不难想到,设 \(g(S)\) 表示只含有 \(S\) 字符集的目标字符串。

初始我们各用一次询问,可以确定 \(g(S),|S|=1\)

对于 \(|S|>1\) 的情况,\(g(S)\) 可以由 \(g(A)\)\(g(B)\),满足 \(A \cap B = \emptyset\)\(A \cup B = S\)

考虑具体的合并方式,比如这样:

\(S\) 表示目前已经合并的字符串,它由 \(a\)\(b\) 合并而来,\(l\)\(r\) 表示两个子字符串的合并到的下标,现在需要确定当前位置是 \(a_l\) 还是 \(b_r\),考虑询问 \(S+a_l+suf_b(r)\) 是否是答案串的子序列,如果是说明当前位置填 \(a_l\),否则填 \(b_r\)。不难发现总的询问次数的上界是 \(|a|+|b|\)

然后决策 \(g\) 的合并过程,一眼看出来是合并果子,根据经典结论,总代价不会超过 \(O(n \log n)\),因为常数很小,所以可以通过。

代码实现

#include<bits/stdc++.h>
using namespace std;
int n;
string s[65];
struct node{
	int len;
	string s;
	bool operator<(const node &a)const{
		return a.len<len;
	}
};
int cnt;
int query(string s){
	int ans;
	cnt++;
	if(cnt>850) assert(0);
	cout<<"? "<<s<<endl;
	cin>>ans;
	return ans;
}
priority_queue<node> q;
string merge(string s1,string s2){
	string s3;
	s3.clear();
	int l=0,r=0;
	for(int i=1;i<=s1.size()+s2.size();i++){
		if(n-query(s3+s1[l]+s2.substr(r))==s3.size()+s2.substr(r).size()+1) s3+=s1[l],l++;
		else s3+=s2[r],r++;
		if(l>=s1.size() || r>=s2.size()) break;
	}
	if(l<s1.size()) s3+=s1.substr(l);
	if(r<s2.size()) s3+=s2.substr(r);
	return s3;
}
string get(char a){
	string s1,s2;
	s1.clear();
	s2.clear();
	for(int i=1;i<=128;i++){
		s1+=a;
	}
	int n=query(s1);
	for(int i=1;i<=128-n;i++){
		s2+=a;
	}
	return s2;
}
int main(){
	for(int i=1;i<=26;i++){
		s[i]=get(i+'A'-1);
		if(s[i].size()) q.push((node){s[i].size(),s[i]});
	}
	for(int i=1;i<=26;i++){
		s[i+26]=get(i+'a'-1);
		if(s[i+26].size()) q.push((node){s[i+26].size(),s[i+26]});
	}
	for(int i=1;i<=10;i++){
		s[i+52]=get(i+'0'-1);
		if(s[i+52].size()) q.push((node){s[i+52].size(),s[i+52]});
	}
	for(int i=1;i<=62;i++){
		n+=s[i].size();
	}
	while(q.size()>1){
		string s1=q.top().s;
		q.pop();
		string s2=q.top().s;
		q.pop();
		string s3=merge(s1,s2);
		q.push((node){s3.size(),s3});
	}
	node s1=q.top();
	cout<<"! "<<s1.s<<endl;
	return 0;
}
//Atcod3rIsGreat
posted @ 2025-02-07 21:56  _Kenma  阅读(5)  评论(0编辑  收藏  举报