每日算法:洛谷U535982 J-A 小梦的AB交换
题目描述
小梦有一个长度为 2∗n 的 AB 串 s,即 s 中只包含 "A" 和 "B" 两种字符,且其中恰好有 n 个 "A" 和 n 个 "B"。
他可以对 s 执行以下操作:
∙ 选择 i,j (1≤i,j≤2⋅n,i=j),并交换 si 和 sj。
他想知道,需要至少多少次操作,才能使得 s 满足相邻的字符不相同,请你帮他算一算吧。
输入格式
本题有多组测试数据。
输入的第一行包含一个正整数 T,表示数据组数。
接下来包含 T 组数据,每组数据的格式如下:
第一行一个正整数 n,表示 s 长度的一半。
第二行一个长度为 2∗n 的字符串 s,保证只由 "A", "B" 两种字符构成。
输出格式
对于每组测试数据:
在单独的一行输出一个整数,表示最少进行的操作次数。
输入输出样例
输入 #1
2 3 AAABBB 3 ABAABB
输出 #1
1 1
说明/提示
【样例 1 解释】
交换 s2=A 和 s5=B,得到 s= "ABABAB",满足题意,一次交换即可。
【数据范围】
令 N 表示 T 组数据中 n 的总和。
对于 50% 的数据有:T=1,1≤N≤3。
对于所有的测试数据有: 1≤T≤100,1≤N≤106。
思考:这一题如果用正向思维去思考,那么会觉得很难,摸不着头脑,但是用逆向思维会发现非常简单!
观察:题目的要求是将原字符串不能有连续的A或B,那么最终答案一定是“ABAB.......”或“BABABA..........”的形式,因此我们可以先构造出这两个最终结果的字符串,然后跟原串进行比较,不相同的地方即为要操作的地方,又因为一次操作可以改变两个位置,我们将最后的结果除2,再对两个答案取最小值,就得到我们最终想要的结果啦
代码:
#include<bits/stdc++.h>
using namespace std;
int t,n;
string s;
int main(){
cin>>t;
while(t--){
cin>>n;
cin>>s;
string s1="",s2="";
//构建两种最终结果的字符串
for(int i = 1;i <= n;i++){
s1+="AB";
s2+="BA";
}
//分别记录得到两种最终结果需要的操作次数
int ans1 = 0,ans2 = 0,ans = 0;
for(int i = 0;i<2*n;i++){
//只要当前位置与预期不相等即认为需要操作
if(s[i] != s1[i]) ans1++;
if(s[i] != s2[i]) ans2++;
}
//一次操作改变两个位置,因此要除以2
ans1/=2;
ans2/=2;
//根据题目要求,取最小值
ans = min(ans1,ans2);
//输出结果
cout<<ans<<endl;
}
return 0;
}