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();
}
}