F. Equalizing Two Strings(Codeforces Round #598 (Div. 3))(思维-模拟)
time limit per test:1 second
memory limit per test:256 megabytes
input:standard input
outputs:tandard output
Description
You are given two strings and both of length and both consisting of lowercase Latin letters.
In one move, you can choose any length len from 1 to n and perform the following operation:
- Choose any contiguous substring of the string of length len and reverse it;
- at the same time choose any contiguous substring of the string of length len and reverse it as well.
Note that during one move you reverse exactly one substring of the string s and exactly one substring of the string .
Also note that borders of substrings you reverse in and in can be different, the only restriction is that you reverse the substrings of equal length. For example, if and , you can reverse and and , but not and .
Your task is to say if it is possible to make strings and equal after some (possibly, empty) sequence of moves.
You have to answer independent test cases.
Input
The first line of the input contains one integer — the number of test cases. Then test cases follow.
The first line of the test case contains one integer — the length of and .
The second line of the test case contains one string consisting of lowercase Latin letters.
The third line of the test case contains one string consisting of lowercase Latin letters.
It is guaranteed that the sum of over all test cases does not exceed .
Output
For each test case, print the answer on it — "YES"
(without quotes) if it is possible to make strings
and
equal after some (possibly, empty) sequence of moves and "NO"
otherwise.
input
4
4
abcd
abdc
5
ababa
baaba
4
asdf
asdg
4
abcd
badc
output
NO
YES
NO
YES
题意
给你两个字符串
和
,长度都是
,都由小写拉丁字母组成。
在一次移动中,您可以选择从
到
的任意长度
并执行以下操作:
选择长度为
的字符串
的任何相邻子字符串并将其反转;
同时选择
长度的字符串
的任何相邻子字符串,并将其反转。
注意,在一个移动过程中,正好反转字符串
的一个子字符串和字符串
的一个子字符串。
还要注意,在
和
中反转的子串的边界可以不同,唯一的限制是反转长度相等的子串。例如,如果
和
,则可以反转
和
和
,但不能反转
和
。
你的任务是说在一些(可能是空的)移动序列之后是否可以使字符串
和
相等。
——来自百度翻译
题解
首先要明白两几个规律:
- 把 和 分别挑一段倒置相当于把 或 单独倒置两次。
- 倒置偶数次相同的位置相当于没有倒置,而且倒置奇数次同一段子串相当于把那一段子串倒置 次,所以题目就要求要分别挑两段不同的子串倒置
- 长度为奇数的倒置可以转化成奇数次相邻两个元素的调换,长度为偶数的倒置可以转换成偶数次相邻元素的调换;例如
abc
转化成cba
需要 次相邻元素的调换位置 ,abcd
转化成dcba
需要 次相邻元素的调换位置 。那么题目要求就可以转化成偶数次相邻元素的调换位置
那么现在题目就变成了让字符串 经过偶数次相邻元素的调换能不能转化成字符串 。
现在还可以先筛选出一些确定的情况:
- 若 中的各个元素的个数和 中的不一样的话是肯定不可能转换成功的。
- 若 或 中有某个元素的个数多于一个的话是肯定能转换成功的。因为这时可以先把 中的这两个元素调换在一起,然后就可以反复调换 中的这两个元素的位置,而在 字符串中调换其他的元素,那就相当于不断变换 的位置,那 当然能变换成任意顺序,最终达到和 相同。
若此时还没有判断出是否可能,那么此时 和 就满足里面的每个元素都不同且两个字符串的元素存在一一对应的关系。
那么就开始递推:
从 中的第一个元素开始,查找 中的对应的元素,假设和 对应的是 ,那么就调换 和 的位置。不过调换前需要判断 是不是偶数,若不是,需要先调换一下 和 (之所以不能调换 中的元素,是因为不能确定调换哪两个对 无影响,若是能找到不影响 的,那也可以,总之调换必须是偶数次就行了),这样就能使 和 是一样的。
循环如此,之后就只需要判断最后两个是否相同就可以判断能否转化了。因为如果只有最后两个不同,那么只有转换奇数次才能相同。
代码
#include<bits/stdc++.h>
using namespace std;
const int MAXA = 4e5;
int n, a[MAXA], b[MAXA], tmp, j;
char s1[MAXA], s2[MAXA];
int solve() {
scanf("%d", &n);
scanf("%s", s1 + 1);
scanf("%s", s2 + 1);
for (int i = 0; i < 26; i++) a[i] = b[i] = 0;
for (int i = 1; i <= n; i++) {
a[s1[i] - 'a']++;
b[s2[i] - 'a']++;
}
for (int i = 0; i < 26; i++)
if (a[i] != b[i])
return printf("NO\n"), 0;
for (int i = 0; i < 26; i++)
if (a[i] > 1 || b[i] > 1)
return printf("YES\n"), 0;
if (n == 1) return printf("YES\n"), 0;
for (int i = 1; i <= n - 2; i++) {
if (s1[i] == s2[i])
continue;
for (j = i + 1; j <= n; j++)
if (s1[i] == s2[j])
break;
if ((j - i) & 1) swap(s1[i + 1], s1[i + 2]);
tmp = s2[j];
for (; j > i; j--)
s2[j] = s2[j - 1];
s2[i] = tmp;
}
if (s1[n] == s2[n])
printf("YES\n");
else
printf("NO\n");
return 0;
}
int main() {
//freopen("in.txt", "r", stdin);
int t;
scanf("%d", &t);
while (t--)
solve();
}