CF1256F Equalizing Two Strings
题目描述
题意
给你两长度都为 \(n\) 的小写字符串 \(S, T\)。
每次操作中你可以任选一个 \(L (1\le L\le n)\),同时翻转 \(S\) 中的任意一个长度为 \(L\) 的子串和 \(T\) 中任意一个长度为 \(L\) 的子串。
请回答你是否能在若干次操作后使两字符串一样?
输入格式
第一行一个正整数 \(q(1\le q\le 10^4)\) 表示询问次数
接下来 \(q\) 组数据,每组数据三行,第一行一个正整数 \(n(1\le n\le 2\times 10^5)\),第二行一个字符串 \(S\),第三行一个字符串 \(T\)。
保证 \(\sum n\le 2\times 10^5\)
输出格式
\(q\) 行,每行一个字符串 YES 或 NO。
输入输出样例 #1
输入 #1
4
4
abcd
abdc
5
ababa
baaba
4
asdf
asdg
4
abcd
badc
输出 #1
NO
YES
NO
YES
算法分析
因为反转操作不会改变字符串中的字符,只会改变他们的顺序,所以两个字符串要每个字符的数量都相同才行,这是条件一。然后分析,因为反转操作很像逆序对问题,把顺序对变成逆序对,所以要两个字符串的逆序对数量的奇偶性相同才行。然后条件二是对每种字符最多出现了一次的情况,但如果有一种字符出现了一次以上,那么一定有解(满足条件一),因为这种字符可以对反转操作进行过渡,所以一定有解,这是条件三。再说一遍,有解的情况是:满足条件一,条件二或条件三满足至少一个就行了,然后这题就完成了。
核心代码
条件一
for(int i = 0; i<26; i++){
if(cnt1[i]!=cnt2[i]){
flag1 = 1;
break;
}
}
if(flag1==1){
cout<<"NO\n";
continue;
}
条件二
for(int i = 0; i<26; i++){
if(cnt2[i]>=2){
flag2 = 1;
break;
}
}
if(flag2==1){
cout<<"YES\n";
continue;
}
条件三
int sum1 = 0;
int sum2 = 0;
for(int i = 1; i<=n; i++){
cnt1[s1[i]-'a']++;
cnt2[s2[i]-'a']++;
for(int j = s1[i]+1-'a'; j<26; j++){
sum1 = (sum1+cnt1[j])%2;
}
for(int j = s2[i]+1-'a'; j<26; j++){
sum2 = (sum2+cnt2[j])%2;
}
}
if(sum1==sum2){
cout<<"YES\n";
}else{
cout<<"NO\n";
}
注意:条件三要在前面,因为后续有用到\(cnt\)数组。
AC代码
#include<bits/stdc++.h>
using namespace std;
int T,n;
int cnt1[35];
int cnt2[35];
int main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin>>T;
while(T--){
memset(cnt1,0,sizeof(cnt1));//多测不清空,爆零两行泪
memset(cnt2,0,sizeof(cnt2));
cin>>n;
string s1,s2;
cin>>s1>>s2;
s1 = " "+s1;//转换为下标为1开始
s2 = " "+s2;
bool flag1 = 0;
bool flag2 = 0;
//条件一
for(int i = 0; i<26; i++){
if(cnt1[i]!=cnt2[i]){
flag1 = 1;
break;
}
}
if(flag1==1){
cout<<"NO\n";
continue;
}
//条件二
for(int i = 0; i<26; i++){
if(cnt2[i]>=2){
flag2 = 1;
break;
}
}
if(flag2==1){
cout<<"YES\n";
continue;
}
//条件三
int sum1 = 0;
int sum2 = 0;
for(int i = 1; i<=n; i++){
cnt1[s1[i]-'a']++;//数量++
cnt2[s2[i]-'a']++;
//这是统计逆序对,因为这里数小,所以不用归并或树状数组优化
for(int j = s1[i]+1-'a'; j<26; j++){
sum1 = (sum1+cnt1[j])%2;
}
for(int j = s2[i]+1-'a'; j<26; j++){
sum2 = (sum2+cnt2[j])%2;
}
}
if(sum1==sum2){
cout<<"YES\n";
}else{
cout<<"NO\n";//到最后了,不要忘记输出NO
}
}
return 0;
}
总结
这道题总体不难,评不到绿题,思路一般,代码好写,只是有一些坑点和注意事项要留心,其他就没什么了。

浙公网安备 33010602011771号