CF1117E Decypher the String
这真的是人能想到的做法?
题意
这是一个交互题。
给定一个由 \(n\) 个小写拉丁字母组成的字符串 \(t\)。该字符串是通过如下方式加密得到的:最初,评测系统有一个由 \(n\) 个小写拉丁字母组成的字符串 \(s\)。然后,他们对 \(s\) 进行了不超过 \(n\) 次(可能为零次)操作。第 \(i\) 次操作用两个整数 \(a_i\) 和 \(b_i\)(\(1 \le a_i, b_i \le n\))表示,表示交换字符串中下标为 \(a_i\) 和 \(b_i\) 的两个字符。所有操作按顺序依次进行。例如,如果 \(s\) 为 xyz,执行以下两次操作:\(a_1 = 1, b_1 = 2\);\(a_2 = 2, b_2 = 3\),那么第一次操作后当前字符串为 yxz,第二次操作后为 yzx,因此 \(t\) 为 yzx。
你的任务是还原原始字符串 \(s\)。不幸的是,你无法获得关于操作序列的任何信息(你甚至不知道是否进行了操作)。但你可以对任意你想要的字符串(只要它只包含小写拉丁字母且长度为 \(n\))执行同样的操作序列,并获得经过这些操作后的结果字符串。
你能否在不超过 \(3\) 次询问的情况下,猜出原始字符串 \(s\)?
对于每个测试,字符串 \(s\) 和交换操作序列都是固定的;交互器不会根据你的解法调整测试数据。
\(1\le n\le10^4\)。
Solution
容易发现,每一操作都是将某一个位置上的字符换到了另一个位置上。简单说,就是有一个函数映射关系 \(f(x)=y\),表示原串第 \(x\) 个字符对应现在的串的第 \(y\) 个字符。于是我们可以想到给每个位置编一个独一无二的号码,以此来方便的找到每个位置的字符的去向。
考虑题目只让我们问三次,我们发现 \(26^2<10000<26^3\),所以我们可以将每个位置编上类似与 aaa、bbb、def 之类的号数,这样每个位置都有一个唯一确定的编号。那么我们就可以通过这个编号推出每个字符的去向。根据上面说的,我们考虑在 \(26\) 进制下编号,第一次询问“百位”的移动,第二次询问“十位”的移动,第三次询问“个位”的移动,最终汇总到一起,就得到了最终的原串。
所以还是非常巧妙的。
Code
//蒟蒻一枚 RP++
#include <bits/stdc++.h>
#define Mem(a,b) memset((a),(b),sizeof((a)))
#define eb emplace_back
#define pb push_back
using namespace std;
using i64 = long long;
using uint = unsigned int;
using ui64 = unsigned long long;
using i128 = __int128;
constexpr int N = 2e5 + 15, mod = 998244353;
constexpr int inf = 1e9;
constexpr double eps = 1e-6, PI = acos (-1);
bool MS;
string t;
int pos[N];
inline string ask (string s) {
cout << "? " << s << endl;
string res;
cin >> res;
return res;
}
inline void report (string s) {
cout << "! " << s << endl;
return ;
}
bool MT;
int main () {
ios::sync_with_stdio(0);
cin.tie (0); cout.tie (0);
cin >> t;
int len = t.size ();
string s1 = "", s2 = "", s3 = "";
for (int i = 0; i < len; ++ i) {
s1 += ('a' + i / 676);
s2 += ('a' + (i / 26) % 26);
s3 += ('a' + i % 26);
}
s1 = ask (s1), s2 = ask (s2), s3 = ask (s3);
string res(len, '#');
for (int i = 0; i < len; ++ i) {
res[(s1[i] - 'a') * 676 + (s2[i] - 'a') * 26 + (s3[i] - 'a')] = t[i];
}
report (res);
cerr << "Memory:" << (&MS - &MT) / 1048576.0 << "MB Time:" << clock() << "ms" << endl;
return 0;
}
/*
1. 该开 long long 的地方你开了吗?
2. 你的数组开够了吗?
3. 该取模的地方你取模了吗?
4. 你有没有理解错题意?
5. 想到了再写
*/

浙公网安备 33010602011771号