CodeForces 603A Alternative Thinking

A. Alternative Thinking
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Kevin has just recevied his disappointing results on the USA Identification of Cows Olympiad (USAICO) in the form of a binary string of length n. Each character of Kevin's string represents Kevin's score on one of the n questions of the olympiad—'1' for a correctly identified cow and '0' otherwise.

However, all is not lost. Kevin is a big proponent of alternative thinking and believes that his score, instead of being the sum of his points, should be the length of the longest alternating subsequence of his string. Here, we define an alternating subsequence of a string as a not-necessarily contiguous subsequence where no two consecutive elements are equal. For example, {0, 1, 0, 1}, {1, 0, 1}, and {1, 0, 1, 0} are alternating sequences, while {1, 0, 0} and {0, 1, 0, 1, 1} are not.

Kevin, being the sneaky little puffball that he is, is willing to hack into the USAICO databases to improve his score. In order to be subtle, he decides that he will flip exactly one substring—that is, take a contiguous non-empty substring of his score and change all '0's in that substring to '1's and vice versa. After such an operation, Kevin wants to know the length of the longest possible alternating subsequence that his string could have.

Input

The first line contains the number of questions on the olympiad n (1 ≤ n ≤ 100 000).

The following line contains a binary string of length n representing Kevin's results on the USAICO.

Output

Output a single integer, the length of the longest possible alternating subsequence that Kevin can create in his string after flipping a single substring.

Sample test(s)
Input
8
10000011
Output
5
Input
2
01
Output
2
Note

In the first sample, Kevin can flip the bolded substring '10000011' and turn his string into '10011011', which has an alternating subsequence of length 5: '10011011'.

In the second sample, Kevin can flip the entire string and still have the same score.


找规律好题!

题目大意:

给一个01组合成的串。在这个字符串的某一个区间里有一次01翻转的机会

问:翻转后的跳跃子串最长多少?

跳跃子串是指,原串的子序列,可以不连续。必须满足相邻的数不同。如1010101010或010101010101这种。像110,10110110就不行。


这题训练的时候YY了一个策略,开始找,后来WA了,没过。想了一个小时,通过枚举了几个串和翻转后其最长跳跃子串的结果,明白了其中的规律。


规律就是:


1.首先,找出在不改变任何区间的情况下,原串里的最长跳跃子串长度cnt。

就是从左到右扫一遍,记下s[i]!=s[i+1]的个数cnt。cnt++;

比如,样例里的,

10000011
满足s[0]!=s[1],s[5]!=s[6];cnt=2;cnt++后cnt=3;

实际上原串的跳跃字串为:101,长度为3.

为了简单写代码,我扫的时候,直接扫到最后一个数.s[n-1]!=s[n],因为s[n]在创建数组的时候栈区默认为数字0.和字符0(ASC码)当然不相等,就可以使cnt多记录一次,从而简单的扫一遍就能得到不改变的情况下,原串的最长跳跃字串的长度。

2.通过一次区间翻转可增加跳跃字串长度只有两种情况。

(1)增加1

(2)增加2

首先,我们要求出出现连数的段数.就是有几段连续0(如00,000,0000)或者连续1(11,111,1111)

第(1)种情况:整个原串里只有一段连续0或者连续1.

如:010010 ,n=6,原串的跳跃字串01010,长度为5

那么对于这种只有1个连0的,最优的翻转的方式便是将连0位置之前的部分全部翻转,翻转后结果,101010,长度为6,增加了1个

第(2)种情况:整个原串里有不少于两段连续0或者连续1

如01001001,n=8,2个连0,跳跃字串为:010101,长度为6

对于这类串,最优的翻转方式,是把两个连0之间的区间全部翻转,翻转结果:01010101,长度为8,增加了2个

。。。。。那如果是3个连0呢,4个连0呢,和两个连0是一样的。因为题目只给一次翻转机会,意味着翻转时只能选择1个区间,对与3个连0,可以有两个区间供选择,4个连0,可以有3个区间供选择,但给这么多区间并没有什么XX用,因为我们只能翻转一次,只能挑一个区间翻转,翻转后其他区间没有变化,和原串对应的部分是一样的,那翻转后便只增加2个跳跃子串长度,所以说,和2个连0是一样情况。

那如果连0是000,0000,00000,这样的呢,和00也是一样的情况。

规律就是这些,写代码的时候还有一点可以优化,就是我并不需要去统计连0和连1的个数

我只需要统计原串的最长跳跃子序列的长度就可以了。

因为如果是(1)中情况,只有一个连00的,那原串的最长跳跃子序列长度必然是n-1.

增加后,最长跳跃子序列的长度必然是n-1+1=n;

如果是(2)中情况,那么原串的最长跳跃子序列长度cnt必然是小于n-1的,

那翻转增加后,长度便是cnt+2,小于等于n.

进一步推理,那么最终的答案只有三种情况、

1.原串的cnt==n

如1010101010,自己就是跳跃序列,翻转后也一样,答案就是n;

2.原串的cnt==n-1,

如1010010101,跳跃序列101010101,长度为n-1,这个时候翻转后可以增加1,所以答案n-1+1=n,依旧是n

3.原串的cnt<n-1

如1010010110,跳跃序列10101010,长度为n-2,这个时候翻转后可以增加2,所以答案是n-2+2,依旧是n

但如果是1101100100,跳跃序列为101010,长度为n-4,这个时候翻转可以增加2,答案是n-4+2=n-2

所以最后的答案只有两个值cnt+2,和n;

而且答案不能超过n,

所以一旦cnt+2>n,说明原串是第1或2种串,此时答案便是n

如果cnt+2<n;说明是3中的串,答案便是cnt+2

经过以上的规律加推理,最后的代码就非常短


#include <stdio.h>
const int MAXN=100005;
char s[MAXN];
int main()
{
        int n,cnt=0;
        scanf("%d%s",&n,s);
        for(int i=0;i<n;i++)
                if(s[i]!=s[i+1])
                        cnt++;
        printf("%d\n",cnt+2>n?n:cnt+2);
        return 0;
}




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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值