codeforces 909 D. Colorful Points

Description

You are given a set of points on a straight line. Each point has a color assigned to it. For point a, its neighbors are the points which don’t have any other points between them and a. Each point has at most two neighbors - one from the left and one from the right.

You perform a sequence of operations on this set of points. In one operation, you delete all points which have a neighbor point of a different color than the point itself. Points are deleted simultaneously, i.e. first you decide which points have to be deleted and then delete them. After that you can perform the next operation etc. If an operation would not delete any points, you can’t perform it.

How many operations will you need to perform until the next operation does not have any points to delete?

Input

Input contains a single string of lowercase English letters ‘a’-‘z’. The letters give the points’ colors in the order in which they are arranged on the line: the first letter gives the color of the leftmost point, the second gives the color of the second point from the left etc.

The number of the points is between 1 and 10 6 .

Output

Output one line containing an integer - the number of operations which can be performed on the given set of points until there are no more points to delete.

Examples

Input
aabb
Output
2

Input
aabcaa
Output
1

Note

In the first test case, the first operation will delete two middle points and leave points “ab”, which will be deleted with the second operation. There will be no points left to apply the third operation to.

In the second test case, the first operation will delete the four points in the middle, leaving points “aa”. None of them have neighbors of other colors, so the second operation can’t be applied.


感谢下面的博主的倾情分析~

https://blog.csdn.net/haut_ykc/article/details/79325344?utm_source=debugrun&utm_medium=referral

题意:给一行由字母 a~z组成的字符串 ,如果有字母与旁边的字母不同,就把他们全部标记并删除,直到不存在这样的字母,求需要几次这样的操作。

分析:

  1. 形如aaaaaaaaaaaaa这样的连续片段,它的内部很长时间是不变的,扫描起来很费时,所以把字符串压缩为字符+长度的表达方式,比如把aaabbbbccc压缩为 {a, b, c} + {3, 4, 3},直接对变化的部分进行关注;
  2. 考虑在新的结构上完成减法,如果一个段和两个段相邻,那么一次操作以后这个段一定会减少两个,而最左边的段和最右边的段只会减少一个。一句话,长度数组首尾每次-1,中间每次-2;
  3. 每轮操作完以后,相邻关系和首尾关系发生变化,考虑更新段的位置。减完后将所有的段重新紧密的排列在一起并更新n。这里需要注意的是,可能会有相同字母的段需要合并到一起;
  4. 考虑什么时候停止。只要段的总个数大于2就将继续

#include<stdio.h>
//#include<iostream>
//using std::cin;
//using std::cout;
#include<algorithm>
using std::sort;
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
#define mabs(x) ((x)>0?(x):(0-(x)))
#define N_max 1000006

int n;
int cnt[N_max];
int f[N_max];
char d[N_max];
int idx;
void upd(int n) {
    if (cnt[n] > 0) {
        if (idx > 0 && d[n] == d[idx - 1]) {//相同的合并
            cnt[idx - 1] += cnt[n]; 
        }
        else{//不同的添在后面
        cnt[idx] = cnt[n];
        d[idx] = d[n];
        idx++;
        }
    }
}


int main() {
    char ch, last = '\0';
    for (n = 0; ~scanf("%c", &ch);)
    {
        if (ch == '\n') break;
        if (last == '\0') {
            last = ch;
            d[n] = ch;
            cnt[n]++;
            continue;
        }
        //压缩为字母+长度
        if (ch == last)cnt[n]++;
        else { cnt[++n] = 1; last = ch; d[n] = ch; }
    }++n;
    if (n == 1) { printf("0"); return 0; }

    int ans = 0, flag = 1;
    for (; flag;) {
        ++ans;
        //首段-1并更新位置
        idx = 0;
        cnt[0]--;
        upd(0);

        for (int i = 1; i < n - 1; ++i) { 
            //中间段-2并更新位置
            cnt[i] -= 2; upd(i);
        } 
        //尾端-1并更新位置
        cnt[n - 1]--;
        upd(n - 1);
        //更新段的个数
        n = idx;
        if (n <= 1)break;
    }
    printf("%d", ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
CodeForces - 616D是一个关于找到一个序列中最长的第k好子段的起始位置和结束位置的问题。给定一个长度为n的序列和一个整数k,需要找到一个子段,该子段中不超过k个不同的数字。题目要求输出这个序列最长的第k好子段的起始位置和终止位置。 解决这个问题的方法有两种。第一种方法是使用尺取算法,通过维护一个滑动窗口来记录\[l,r\]中不同数的个数。每次如果这个数小于k,就将r向右移动一位;如果已经大于k,则将l向右移动一位,直到个数不大于k。每次更新完r之后,判断r-l+1是否比已有答案更优来更新答案。这种方法的时间复杂度为O(n)。 第二种方法是使用枚举r和双指针的方法。通过维护一个最小的l,满足\[l,r\]最多只有k种数。使用一个map来判断数的种类。遍历序列,如果当前数字在map中不存在,则将种类数sum加一;如果sum大于k,则将l向右移动一位,直到sum不大于k。每次更新完r之后,判断i-l+1是否大于等于y-x+1来更新答案。这种方法的时间复杂度为O(n)。 以上是两种解决CodeForces - 616D问题的方法。具体的代码实现可以参考引用\[1\]和引用\[2\]中的代码。 #### 引用[.reference_title] - *1* [CodeForces 616 D. Longest k-Good Segment(尺取)](https://blog.csdn.net/V5ZSQ/article/details/50750827)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] - *2* [Codeforces616 D. Longest k-Good Segment(双指针+map)](https://blog.csdn.net/weixin_44178736/article/details/114328999)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^koosearch_v1,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值