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

总结

这道题总体不难,评不到绿题,思路一般,代码好写,只是有一些坑点和注意事项要留心,其他就没什么了。

posted @ 2026-09-05 22:37  xmgene  阅读(8)  评论(0)    收藏  举报