Atcoder abc399 E题题解

Atcoder abc399 E题题解

题意

image

思路

坑点在于是要把 \(S\) 中的 每一个改变

考虑把它转换为如下两个问题:

  • 是否可以变
  • 最小的步数

这个题可以考虑维护一个映射关系 \(f\)

就是每一个 \(S\) 对应的 \(T\) 是什么。

如果有如下一个样例:

\(\text{AA}\)

\(\text{BC}\)

我们来手动模拟一下。

  1. \(f_{'A'}='B'\)
  2. \(f_{'A'}='C'\)

显然,这不可能,所以我们找到了第一个不满足条件的关系。

就是映射不唯一

那然后考虑第二种样例:

\(\text{ABCDEFGHIJKLMNOPQRSTUVWXYZ}\)

\(\text{BCDEFGHIJKLMNOPQRSTUVWXYZA}\)

好像……也是无解的。

不急,再来看一下第三组:

\(\text{ABCD}\)

\(\text{BCDA}\)

这个,好像可以。

我们具体是怎么做的呢?

  1. \(S\) 中所有的 \(D\) 都变成 \(Z\)
  2. \(C\) 变成 \(D\)
  3. \(B\) 变成 \(C\)
  4. \(A\) 变成 \(B\)
  5. \(Z\) 变成 \(A\)

完美。

那为什么这个行但是上一组不行呢?

显然是因为我们引入了一个外部字符进行更改。

为什么第二组不行呢?因为我们没有可用的外部字符。

这个过程非常像什么呢?

非常像图论中的 破环成链

考虑啊把整个问题看成一个图论问题。

是一个有 \(26\) 个节点,每个结点的出度为 \(1\) 的图。

只可能有以下几种情况。

  1. 孤点。
  2. 自环。
  3. 环。
  4. 基于自环的树。
  5. 基环树(不是自环)。

考虑怎么破环成链。

可以看这里。

video

所以我们现在有了思路。

image

直接做就行了。

要注意,需要先判断可不可行,然后求最小步骤。

具体的看代码。

代码

#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";
}

后记

atcoder better安装

posted @ 2025-04-03 22:08  guoguo160  阅读(17)  评论(0)    收藏  举报