F - Equalizing Two Strings

题意:有两个等长字符串s,t,每次选择一个长度,把s的这个长度的某区间和t的这个长度的某区间同时翻转,问能否使得s与t相等。

题解:首先排序之后相同才有可能有解,那除此之外什么时候无解呢?设想每次翻转的区间长度都是2,变成一个临位交换,那么一次交换会使得逆序数变化1(冒泡排序),直觉感觉是长的翻转都是分解成这种临位交换的,那么s和t的逆序数会同时变化,所以只需要逆序数的差为偶数,那么可以让逆序数小的那个原地反复交换浪费掉差值。需要注意的是假如有某个字符出现了两次,那么这两个字符在排序之后就可以原地交换浪费掉差值。想不到1A了,说不定这些直觉和乱搞能力已经达到2200了,只是
Graphsforces 要注意学图的知识。

注意归并排序的时候,逆序数应该是longlong,而且只有在弹出j才增加逆序数为剩余的i的数量。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;

char s[200005], t[200005], tmp[200005];

ll mergesort(char *s, int l, int r) {
    if(l == r)
        return 0;
    int m = l + r >> 1;
    ll res = 0;
    res += mergesort(s, l, m);
    res += mergesort(s, m + 1, r);
    int i = l, j = m + 1, k = 0;
    while(i <= m || j <= r) {
        if(i > m)
            tmp[++k] = s[j++];
        else if(j > r)
            tmp[++k] = s[i++];
        else if(s[i] < s[j])
            tmp[++k] = s[i++];
        else {
            res += m - i + 1;
            tmp[++k] = s[j++];
        }
    }
    for(int i = 1; i <= k; ++i)
        s[l + i - 1] = tmp[i];
    return res;
}

void test_case() {
    int n;
    scanf("%d%s%s", &n, s + 1, t + 1);
    ll rs = mergesort(s, 1, n);
    ll rt = mergesort(t, 1, n);
    bool suc = 0;
    if(strcmp(s + 1, t + 1) == 0) {
        int tmp = unique(s + 1, s + 1 + n) - (s + 1);
        if(tmp != n || (rs - rt) % 2 == 0)
            suc = 1;
    }
    if(suc)
        puts("YES");
    else
        puts("NO");
}

int main() {
#ifdef KisekiPurin
    freopen("KisekiPurin.in", "r", stdin);
#endif // KisekiPurin
    int t = 1;
    scanf("%d", &t);
    for(int ti = 1; ti <= t; ++ti) {
        //printf("Case #%d: ", ti);
        test_case();
    }
}
01-06 23:21