Atcoder abc399 E题题解
Atcoder abc399 E题题解
题意

思路
坑点在于是要把 \(S\) 中的 每一个改变。
考虑把它转换为如下两个问题:
- 是否可以变
- 最小的步数
这个题可以考虑维护一个映射关系 \(f\)。
就是每一个 \(S\) 对应的 \(T\) 是什么。
如果有如下一个样例:
\(\text{AA}\)
\(\text{BC}\)
我们来手动模拟一下。
- \(f_{'A'}='B'\)
- \(f_{'A'}='C'\)
显然,这不可能,所以我们找到了第一个不满足条件的关系。
就是映射不唯一。
那然后考虑第二种样例:
\(\text{ABCDEFGHIJKLMNOPQRSTUVWXYZ}\)
\(\text{BCDEFGHIJKLMNOPQRSTUVWXYZA}\)
好像……也是无解的。
不急,再来看一下第三组:
\(\text{ABCD}\)
\(\text{BCDA}\)
这个,好像可以。
我们具体是怎么做的呢?
- 令 \(S\) 中所有的 \(D\) 都变成 \(Z\)。
- \(C\) 变成 \(D\)。
- \(B\) 变成 \(C\)。
- \(A\) 变成 \(B\)。
- \(Z\) 变成 \(A\)。
完美。
那为什么这个行但是上一组不行呢?
显然是因为我们引入了一个外部字符进行更改。
为什么第二组不行呢?因为我们没有可用的外部字符。
这个过程非常像什么呢?
非常像图论中的 破环成链。
考虑啊把整个问题看成一个图论问题。
是一个有 \(26\) 个节点,每个结点的出度为 \(1\) 的图。
只可能有以下几种情况。
- 孤点。
- 自环。
- 环。
- 树
- 基于自环的树。
- 基环树(不是自环)。
考虑怎么破环成链。
可以看这里。
所以我们现在有了思路。

直接做就行了。
要注意,需要先判断可不可行,然后求最小步骤。
具体的看代码。
代码
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5+10;
int n;
string s, t;
unordered_map < char, int > mp, f, indeg, vis;
int ans;
char rt;
inline void dfs(int x) {
if(x == 0) {
return;
}
if(vis[x]) {
if(x == rt) {
ans++;
}
return;
}
vis[x] = 1;
dfs(mp[x]);
}
signed main() {
cin >> n >> s >> t;
s = ' ' + s;
t = ' ' + t;
for(int i = 1; i <= n; ++i) {
if(mp[s[i]] && mp[s[i]] != t[i]) {
cout << -1 << "\n";
exit(0);
}
mp[s[i]] = t[i];
f[t[i]] = 1;
}
int res = 0;
for(int i = 'a'; i <= 'z'; ++i) {
res += f[i];
}
if(res == 26 && s != t) {
cout << -1 << "\n";
return 0;
}
for(int i = 'a'; i <= 'z'; ++i) {
if(mp[i] == i) mp[i] = 0;
ans += (mp[i] == 0) ? 0 : 1;
indeg[mp[i]]++;
}
for(int i = 'a'; i <= 'z'; ++i) {
if(indeg[i] >= 2) {
if(!vis[i]) {
dfs(i);
}
}
}
for(int i = 'a'; i <= 'z'; ++i) {
if(!vis[i]) {
rt = i;
dfs(i);
}
}
cout << ans << "\n";
}

浙公网安备 33010602011771号