题解:[AGC044D] Guess the Password
前言
比较可做的交互题,瓶颈在于编辑距离的转化。
思路分析
首先考虑编辑距离是困难的,考虑弱化条件。
因为本题要求确定一个字符串,因此,可以尝试将编辑距离转化为判定子序列相关的信息。
具体地,考虑,对于两个字符串 , 是 的子序列当且仅当 。
所以我们可以用编辑距离来判定子序列。
这样,我们不难想到,设 表示只含有 字符集的目标字符串。
初始我们各用一次询问,可以确定 。
对于 的情况, 可以由 和 ,满足 ,。
考虑具体的合并方式,比如这样:
设 表示目前已经合并的字符串,它由 和 合并而来, 和 表示两个子字符串的合并到的下标,现在需要确定当前位置是 还是 ,考虑询问 是否是答案串的子序列,如果是说明当前位置填 ,否则填 。不难发现总的询问次数的上界是 。
然后决策 的合并过程,一眼看出来是合并果子,根据经典结论,总代价不会超过 ,因为常数很小,所以可以通过。
代码实现
#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
本文作者:Kenma
本文链接:https://www.cnblogs.com/Kenma/p/18703271
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步