题目描述
迫切希望在郡县集市上赢得最佳奶牛摄影师的农夫约翰正在尝试为他的 N头奶牛拍摄一张完美的照片。
农夫约翰拥有两种品种的奶牛:更赛牛(Guernsey)和荷斯坦牛(Holstein)。
为了使他的照片尽可能地艺术,他想把他的奶牛排成一排,使得尽可能多的更赛牛处于队列中的偶数位置(队列中的第一个位置是奇数位置,下一个是偶数位置,以此类推)。
由于他与他的奶牛缺乏有效的沟通,他可以达到目的的唯一方法是让他的奶牛的偶数长的「前缀」进行反转(一个前缀指的是对于某个位置 j,从第一头奶牛到第 j头奶牛范围内的所有奶牛)。
请计算农夫约翰达到目的所需要的最小反转次数。
输入格式
输入的第一行包含 N的值。
第二行包含一个长为 N的字符串,给出初始时所有奶牛从左到右的排列方式。每个 H
代表一头荷斯坦牛,每个 G
代表一头更赛牛。
输出格式
输出一行,包含达到目的所需要的最小反转次数。
数据范围
2≤N≤2×10^5,N为偶数。
输入样例:
14
GGGHGHHGHHHGHG
输出样例:
1
样例解释
在这个例子中,只需反转由前六头奶牛组成的前缀即可。
GGGHGHHGHHHGHG (反转前)
-> HGHGGGHGHHHGHG (反转后)
在反转之前,四头更赛牛处于偶数位置。
反转后,六头更赛牛处于偶数位置。不可能使得超过六头更赛牛处于偶数位置。
题解
对于一个偶数序列,如HHHGHGGHHGGG,下标位置从1开始,可以看作两个字母一组。分组情况为HH、GG、HG、GH,为了让更多的G处于偶数位置,很显然,对于HH和GG的反转是无效的。
将HH、GG看作X,GH看作1,HG看作0,原序列为X0010X,让更多的G处于偶数位置,即通过前缀反转把更多的0变成1。通过分析可以得出,存在最优解即可以把原序列都变成1。题目要求最少操作次数,针对于每个不同的相邻序列如0010中的01,必须通过一次操作把00进行翻转,变为111,原序列变成1110;依照此原则继续反转,反转为0000。此时进行特判,若序列全为0则需要整体进行翻转变为1111,否则不需要反转。
因此,最少反转次数即序列中不同元素的位置(需模拟反转遍历判断)+特判位置。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 2e5+10;
int w[N] ,ans, m;
int main()
{
int n;
cin>>n;
string s;
cin>>s;
for(int i=0;i<s.size();i+=2){
if(s[i] != s[i+1]){
w[m++] = s[i]=='G'; //用w数组记录原序列的01状态(GH、HG状态)
}
}
for(int i=0;i<m;i++){
if(w[i]!=w[i+1]) ans++; //若不同则需要翻转一次
}
//这里因为w数组初始为全0,而下标用到了i+1,相当于进行了特判。
printf("%d\n", ans);
return 0;
}