D. Prefixes and Suffixes(字符串/思维/回文串)

题目
参考

题意

给定2个长度为n的字符串s1,s2。给定操作:

  • 选择整数k<=n
  • 将字符串s1的前k个元素,和字符串s2的后k个元素,做交换。

比如n=5, k=2,则s1[1,2], s2[4,5] = s2[4,5], s1[1,2]

可以执行上述操作任意次,问最终,s1和s2能否相等。相等输出YES,否则输出NO

思路

我们观察发现,字符串s1的第i个元素和字符串s2的倒数第i个元素,1<=i<=n,我们发现,这2个元素的相对位置都保持不变。因为每次交换,s1的第i个元素(i<=k),就是交换到了s2的倒数第i个位置。

利用上述这一发现,我们来构建无序元素对(s1[i],s2[n+1-i])(1<=i<=n),如果这些无序元素对:

  • 出现次数为奇数次的,满足该元素对两个的值相等,即s1[i]==s2[n+1-i];
  • 且出现次数为奇数次的,数量不超过1
    那么则可以最终使s1==s2

证明:
如果满足上述2个条件,说明s1+reverse(s2)可以构成回文字符串。此时s1==s2

其次,还有一个必要条件,s1上第i个元素的位置(或者s2上倒数第i个元素),可以放置到s1的[1,n]任意一个位置。

假设s1的大于i的位置已经放置好了。现在我们要将s1的第j个元素放置到第i个位置。

  • 令k=j,此时我们则可以将s1的第j个位置,交换到s2的最后一个位置
  • 如果我们需要交换元素对(因为我们上面提到的元素对,都是无序的),则可以令k=1,将该元素对交换。
  • 令k=i,此时s2的最后一个位置的元素,就被交换到s1的第i个位置。

如下例子,原始j=2,目标i=4
D. Prefixes and Suffixes(字符串/思维/回文串)_第1张图片

贴一个官方样例
D. Prefixes and Suffixes(字符串/思维/回文串)_第2张图片

代码

#include 
using namespace std;
#define ll long long
#define pcc pair
#define inf 0x3f3f3f3f
const int maxn = 200010;

int n;
char s[maxn], s2[maxn];

map<pcc, int> mp;
void solve() {
    scanf("%d", &n);
    scanf("%s%s", s, s2);
    mp.clear();
    for (int i = 0; i < n; ++i) {
    	char a = s[i], b = s2[n-1-i];
    	if (a > b) {
    		swap(a, b);
		}
		++mp[{a, b}];
	}
	int tot = 0;
	bool flag = true;
	for (auto p: mp) {
		if (p.second % 2 == 0) { // skip even number
			continue;
		}
		pcc tmp = p.first;
		// 1. if pair has odd number, with different elements
		if (p.first.first != p.first.second) {
			flag = false;
			break;
		}
		++tot;
	}
	// 2. num of pair with odd number should not over 1.
	flag = flag && (tot < 2);
	printf("%s\n", flag ? "YES" : "NO");
    
}

int main() {
    int t;
    scanf("%d", &t);
    while (t--) {
    	solve();
	}
}

你可能感兴趣的:(Codeforces,算法)