AGC044D Guess the Password 题解

题目链接:AGC044D - Guess the Password

首先我们想先知道整个字符串的长度,发现你可以问长为 $ \text{128} $ 的同一个字符的字符串,这样可以问出每个字符在字符串中出现了多少次,然后我们想把两个已知是圆字符串的子序列的字符串合并是容易的,类似归并排序一样做就可以做到 $ O(|\sum |+Llog|\sum|) $ 次操作。

代码:

#include<bits/stdc++.h>
#define pb push_back
using namespace std;

int ask(string &s)
{
	cout<<"? "<<s<<endl;
	int x;
	cin>>x;
	return x;
}
int len;
string merge(string a,string b)
{
	if(!a.size())return b;
	if(!b.size())return a;
	string c="";
	for(int i=0,j=0;i<a.size()||j<b.size();)
	{
		if(i==a.size())c+=b[j++];
		else if(j==b.size())c+=a[i++];
		else
		{
			string tmp=c+a[i]+b.substr(j);
			if(ask(tmp)==len-tmp.size())c+=a[i++];
			else c+=b[j++]; 
		}
	}
	return c;
}
string solve(vector<string> vc)
{
	if(vc.size()==1)return vc[0];
	vector<string> vcl,vcr;
	for(int i=0;i<vc.size()/2;i++)
	{
		vcl.pb(vc[i]);
	}
	for(int i=vc.size()/2;i<vc.size();i++)
	{
		vcr.pb(vc[i]);
	}
	return merge(solve(vcl),solve(vcr));
}
signed main()
{
	vector<char> ch;
	for(int i='a';i<='z';i++)
	{
		ch.pb(i);
	}
	for(int i='A';i<='Z';i++)
	{
		ch.pb(i);
	}
	for(int i='0';i<='9';i++)
	{
		ch.pb(i);
	}
	vector<string> vc;
	for(auto x:ch)
	{
		string s="";
		for(int i=1;i<=128;i++)
		{
			s+=x;
		}
		int cur=128-ask(s);
		len+=cur;
		s="";
		for(int i=1;i<=cur;i++)
		{
			s+=x;
		}
		vc.pb(s);
	}
	string ans=solve(vc);
	cout<<"! "<<ans<<endl;
}
posted @ 2026-09-07 16:58  MCYYDS  阅读(9)  评论(0)    收藏  举报