[CF1730D] Prefixes and Suffixes 题解
首先发现后缀和前缀比较不好看,所以翻转第二个字符串,记为 \(T'\)。
这样就变成了操作两个字符串的前缀。
观察发现,操作 \(k\) 等价于交换 \(S[1\sim k]\) 和 \(T'[1\sim k]\),然后翻转 \(S[1\sim k]\) 和 \(T'[1\sim k]\)。
结论 1:同一个下标上的字符对恒定。
因为我们所有的操作都不会改变同一个下标上的字符的对应关系。
有了这个结论,可以把两个字符串看做一个有多个二元组的序列 \(P\)。
结论 2:经过有限次操作,可以得到任意一个 \(P\) 的排列。
如果我们想得到排列 \(P'\),使用数学归纳法。
假设 \(P'[j + 1\sim n]\) 已经得到,现在需要将 \(P[i]\) 移到 \(j\),可以先使用操作 \(i\),将它移到开头,再使用操作 \(j\),将 \(i\) 移到 \(j\)。
归纳得证。
结论 3:同一个下标上的字符对可以任意交换。
假设需要交换下标为 \(i\) 的字符对,先使用操作 \(i\),重新排列之后,使用操作 \(i - 1\) 还原被操作 \(i\) 多影响的下标。
因此字符对是无序的。
所以综上所述,如果 \(n\) 是偶数,相同的字符对出现次数一定要是偶数,否则无法对应,如果 \(n\) 是奇数,可以容许存在一个两个字符相同的字符对,出现次数为奇数,将其放在序列的中间部分,其余出现次数要是偶数。
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
#define x first
#define y second
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5 + 10;
map<PII, int> cnt;
void work() {
int n;
string a, b;
cin >> n >> a >> b;
for(int i = 0, j = n - 1; i < n; i ++, j --)
cnt[{min(a[i] - '0', b[j] - '0'), max(a[i] - '0', b[j] - '0')}] ++;
int flg = 0;
for(auto [a, b] : cnt) if(b & 1) flg ++;
if(!flg) cout << "YES\n";
else if(flg == 1 && (n & 1)) cout << "YES\n";
else cout << "NO\n";
}
signed main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int T;
cin >> T;
while(T --) work();
return 0;
}