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\),所以我们可以将每个位置编上类似与 aaabbbdef 之类的号数,这样每个位置都有一个唯一确定的编号。那么我们就可以通过这个编号推出每个字符的去向。根据上面说的,我们考虑在 \(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. 想到了再写
*/
posted @ 2026-05-03 09:55  XXh_Laoxu  阅读(7)  评论(0)    收藏  举报

转载请注明出处!


#页面摧毁游戏#
使用【上下左右】控制飞行器的运动
使用【空格】发射导弹
点击开始摧毁