思路
题目的要求本质上不是让字母对应某个固定数字,而是要求两个字符串简化后完全一致。
例如字符串 motor 中,第 \(1\) 个和第 \(4\) 个字符都是 m,所以对应的数字第 \(1\) 位和第 \(4\) 位也必须相同;其他不同字母对应的数字也必须互不相同。
因此我们可以把一个字符串转化成一种标准形式,只记录每个字符第一次出现的顺序。
例如 motor:
m第一次出现,编号为 \(1\);o第一次出现,编号为 \(2\);t第一次出现,编号为 \(3\);- 再次遇到
o,所以编号为 \(2\); r第一次出现,编号为 \(4\)。
所以 motor 可以标准化成 12324。
同理,一个数字也可以按照相同方法标准化。比如 10607 中,不同数字第一次出现的顺序也是 12324,因此它满足条件。
于是问题就变成:找到一个质数 \(P\),使得 solve(S) == solve(to_string(P))。
因为 \(|S|\le7\),所以满足条件的质数一定不会超过 \(10^7-1\)。因此可以直接使用埃氏筛枚举 \(2\) 到 \(10^7\) 的所有质数,每遇到一个质数,就判断它的标准形式是否和 \(S\) 相同。
如何想到
题目里最关键的一句话是:对于任意 \(i<j\),有 \(S_i=S_j\) 当且仅当 \(T_i=T_j\)。
这里其实完全不关心具体是什么字母或者数字,只关心哪些位置相等。
所以自然可以把字母和数字都重新编号。例如第一次出现的字符记成 \(1\),第二种新字符记成 \(2\),之后遇到相同字符就继续用原来的编号。
这样只要两个字符串标准化后的结果相同,它们的位置相等关系就完全相同。
而字符串长度最多只有 \(7\),所以质数范围最多到 \(10^7\),直接筛出所有质数并逐个判断即可。
代码
#include <bits/stdc++.h>
#define rep(i,j,k) for (int i = (j); i <= (k); i ++)
#define per(i,j,k) for (int i = (j); i >= (k); i --)
#define uint unsigned int
#define ll long long
#define ull unsigned long long
#define db double
#define ldb long double
#define mkp make_pair
#define eb emplace_back
#define e_ emplace
#define ls (p << 1)
#define rs (p << 1 | 1)
//#define int ll
using namespace std;
const int N = 1e7 + 5;
//const int MOD = 998244353;
//const int MOD = 1000000007;
const int INF = 0x3f3f3f3f;
const ll LINF = 4e18;
//int T;
string s;
bool p[N];
string solve (string t) {
map<char, int> mp;
int cnt = 0;
string ans = "";
for (char c : t) {
if (mp[c] == 0) {
mp[c] = ++ cnt;
ans += char ('0' + cnt);
}
else ans += char ('0' + mp[c]);
}
return ans;
}
signed main () {
//freopen (".in", "r", stdin);
//freopen (".out", "w", stdout);
ios::sync_with_stdio (0);
cin.tie (0);
cin >> s;
s = solve (s);
rep (i, 2, 1e7) {
if (!p[i]) {
if (s == solve (to_string (i))) {
cout << i;
return 0;
}
for (int j = i + i; j <= 1e7; j += i) p[j] = true;
}
}
cout << -1;
return 0;
}
复杂度
埃氏筛的时间复杂度为 \(O(M\log\log M)\),其中 \(M=10^7\)。
对于每个质数还会进行一次长度最多为 \(7\) 的字符串标准化,因此这部分可以看作 \(O(M)\)。
总时间复杂度可以看作 \(O(M\log\log M)\)。
浙公网安备 33010602011771号