算法每日一题:照相

1.题目描述

        迫切希望在郡县集市上赢得最佳奶牛摄影师的农夫约翰正在尝试为他的 NN 头奶牛拍摄一张完美的照片。农夫约翰拥有两种品种的奶牛:更赛牛(Guernsey)和荷斯坦牛(Holstein)。为了使他的照片尽可能地艺术,他想把他的奶牛排成一排,使得尽可能多的更赛牛处于队列中的偶数位置(队列中的第一个位置是奇数位置,下一个是偶数位置,以此类推)。由于他与他的奶牛缺乏有效的沟通,他可以达到目的的唯一方法是让他的奶牛的偶数长的「前缀」进行反转(一个前缀指的是对于某个位置 jj,从第一头奶牛到第 jj 头奶牛范围内的所有奶牛)。请计算农夫约翰达到目的所需要的最小反转次数。

2.输入格式

输入的第一行包含 N 的值。

第二行包含一个长为 N 的字符串,给出初始时所有奶牛从左到右的排列方式。每个 H 代表一头荷斯坦牛,每个 G 代表一头更赛牛。

3.输出格式

输出一行,包含达到目的所需要的最小反转次数。

4.数据范围

2≤N≤2×1052≤N≤2×105,N 为偶数。

5.输入样例:

14
GGGHGHHGHHHGHG

输出样例:

1

6.样例解释

在这个例子中,只需反转由前六头奶牛组成的前缀即可。

   GGGHGHHGHHHGHG (反转前)
-> HGHGGGHGHHHGHG (反转后)

在反转之前,四头更赛牛处于偶数位置。

反转后,六头更赛牛处于偶数位置。不可能使得超过六头更赛牛处于偶数位置。

7.问题解析:

        性质:将牛两两分组,反转后组内的牛不变,但组内牛的顺序会反转

        例如:对第1,2组反转 GG GH  -> HG  GG;第1,2,3组反转 GG GH GH -> HG HG GG。

        两两分组可得四种情况,即 GG ,HH,GH,HG ,题目要求使得尽可能多的更赛牛处于队列中的偶数位置(队列中的第一个位置是奇数位置,下一个是偶数位置,以此类推),即对于组内,要求G尽可能处于第二个位置(每组第二个位置一定是偶数位),即 _G ,对于GG和HH,经过反转无法调整位置,而GH和HG可以相互转换,对此可以将GH和HG视为两个状态(1/0),而GG和HH则不需做任何处理直接忽略,则上图序列可以转换为

        而我们要做的便是通过前缀反转获得尽可能多的 0,但该序列通过前缀反转一定可以全部转为0(这里不做证明,因为本人也不太会。。),所以最终的结果是将该串序列全部变为0。

        最终我们将问题转换为,将01序列通过前缀反转全部转为0至少需要多少次,这里可以选择一种贪心做法:在序列中如果出现****01*****(或者*****10*****)我们则对到0(到1)的前缀进行一次反转。例如:

再举一个更加复杂的例子:

 这里我们要注意最后一位如果是1则还需要加一次反转将所有1转为0,在代码中定义数组是全局变量的话默认多余位置为0,可以不用去做特殊处理

这里我们给出详细代码:

#include <iostream>

using namespace std;
const int N = 200010;
int n,k;
char str[N];
int w[N];

int main(){
    cin>>n>>str;
    
    for(int i=0;i<n;i+=2){
        if(str[i] != str[i+1]){
            w[k++] = str[i] == 'G';
        }
    }
    
    int res = 0;
    for(int i=0;i<k;i++){
        if(w[i]!= w[i+1]) res++; 
    }
    
    cout<<res;
    
    return 0;
}

注:本题解为个人在Acwing网站学习所得4440. 照相 - AcWing题库,未经允许,禁止转载!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值