题目大意:这是一道交互题。给你一个长度为n的字符串,这个字符串是经过规则变换的,题目不告诉你变换规则,但是允许你提问3次:每次提问你给出一个长度为n的字符串,程序会返回按变换规则变换后的字符串,提问3次后你需要猜出这个字符串。解法是学习https://blog.csdn.net/baiyifeifei/article/details/87807822 这个博主的,借用了进制的思想非常巧妙。
解法:对于某个位置的来源位置我们设为x,因为26*26*26>10000,那么x可以唯一表示为x=a*26*26+b*26+c。那么我们只要想办法求出a,b,c就能得到它的来源位置。
那么怎么利用三次询问求a,b,c?我们首先构造(26*26个a) (26*26个b) (26*26个c)......(26*26个z),设此位置变换后的字符为c[0],那么a=c[0]-‘a‘(可以理解为a=x/(26*26)=c[0]-‘a‘)。道理类似的我们下一次构造(26个a) (26个b) (26个c) ......(26个d)的字符串让程序变换,此时变换后的字符为c[1],那么b=c[1]-‘a‘(可以理解为b=x%(26*26) /26=(b*26+c)/26=c[1]-‘a‘),这里的b可能有点儿难理解,为什么是这样得到的c[1]就是(b*26+c)/26?因为前一个询问我们已经确定x在a这一个(26*26)的大块里面了,那么我们只需要考虑这个大块,把这个大块再细分为26块看看返回什么值就能知道x在a这个大块的哪一个小块b里面。道理类似的最后构造(abc..z)(abc..z)...(abc..z)得到c=c[2]-‘a‘。
那么我们就得到该位置的来源是a*26*26+b*26+c,问题得到解决。
如果还是感觉难以理解,可以看看代码再仔细想想:
#include<bits/stdc++.h> using namespace std; const int N=10000+10; int n; char s[N],q[3][N],g[3][N],ans[N]; int main() { scanf("%s",s); n=strlen(s); for (int i=0;i<n;i++) { q[0][i]=(i/(26*26)%26+‘a‘); q[1][i]=(i/26%26+‘a‘); q[2][i]=(i%26+‘a‘); } for (int i=0;i<3;i++) { printf("? %s\n",q[i]); fflush(stdout); scanf("%s",g[i]); } for (int i=0;i<n;i++) { int tmp=(g[0][i]-‘a‘)*26*26+(g[1][i]-‘a‘)*26+(g[2][i]-‘a‘); ans[tmp]=s[i]; } printf("! %s",ans); return 0; }
原文地址:https://www.cnblogs.com/clno1/p/10420899.html