E. Decypher the String
题意
就是给你一个长度为n的字符串的转换规则,规则是最多可以交换任意两个位置n次,得到新的字符串,现在给你一个转换之后的字符串,让你求原来的字符串。
最多提问三次,每次提问你给出一个长度为n的字符串,交互会按照规则返回转换之后的字符串。
1
≤
n
≤
1
0
4
1 \leq n \leq 10^4
1≤n≤104
做法
这道题不考虑那个转换规则,我们只知道最后每个位置一定由之前字符串的某个位置而来,而且是一一对应的。所以我们只要知道每个字符之前在哪个位置就可以,我们第一次提问用一个
26
∗
26
∗
a
,
26
∗
26
∗
b
,
26
∗
26
∗
c
.
.
.
.
.
26
∗
26
∗
z
26*26*a,26*26*b,26*26*c.....26*26*z
26∗26∗a,26∗26∗b,26∗26∗c.....26∗26∗z 这样的字符串提问,我们就知道每个字符来自哪一个块中,之后再用
26
∗
a
,
26
∗
b
,
26
∗
c
.
.
.
.
26
∗
z
26*a,26*b,26*c....26*z
26∗a,26∗b,26∗c....26∗z这样的字符串提问,就知道这个字符来自哪一个小块,因为之前确定大块,而每个大块只包含26种小块,所以可以根据答案判断这个位置来自哪个大块的哪个小块。同理最后用
a
,
b
,
c
,
d
.
.
.
z
a,b,c,d...z
a,b,c,d...z去提问,就知道每个字符来自哪个位置了,其实仔细想一下就是一个26进制。因为
2
6
3
>
10000
26^3>10000
263>10000 ,所以每个位置都有唯一的对应关系。
代码
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<map>
using namespace std;
const int maxn = 1e5+5;
char str[maxn],tmp[maxn];
char ans[3][maxn];
char rrs[3][maxn];
map<string,int> mp;
char ou[maxn];
int main()
{
scanf("%s",tmp);
int len=strlen(tmp);
for(int i=0;i<len;i++)
{
ans[0][i]=char(i/(26*26)+'a');
ans[1][i]=char((i%(26*26))/26+'a');
ans[2][i]=char(i%26+'a');
string res="";
res+=ans[0][i];
res+=ans[1][i];
res+=ans[2][i];
mp[res]=i;//i位置三次查询串的字符为res
}
for(int i=0;i<3;i++) ans[i][len]='\0';
cout<<"?"<<" "<<ans[0]<<endl;
scanf("%s",str);
for(int i=0;i<len;i++) rrs[0][i]=str[i];
cout<<"?"<<" "<<ans[1]<<endl;
scanf("%s",str);
for(int i=0;i<len;i++) rrs[1][i]=str[i];
cout<<"?"<<" "<<ans[2]<<endl;
scanf("%s",str);
for(int i=0;i<len;i++) rrs[2][i]=str[i];
for(int i=0;i<len;i++)
{
string res="";
res+=rrs[0][i];
res+=rrs[1][i];
res+=rrs[2][i];
ou[mp[res]]=tmp[i];
}
ou[len]='\0';
cout<<"!"<<" "<<ou<<endl;
return 0;
}