[CF1730D] Prefixes and Suffixes 题解

发布时间 2023-08-16 21:36:33作者: MoyouSayuki

首先发现后缀和前缀比较不好看,所以翻转第二个字符串,记为 \(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;
}