结贴!!终于磨出来了!!这题放了好久,想不出怎么处理那个超长的字符串。但其实转换思路。并不需要模拟题目所述的操作,我们只需要知道结果就好了。
换个思路来分析:
题目要求的答案是字符串中(经过处理的或未经过处理的)最长的交替01
子序列,注意是子序列,不是连续子序列,也不是子串。
也就意味着字符串中只有若干连续的0或者连续的1不起作用。
比方说:010(00)10(11)1,这个01串分别有两个0和两个1连在一起不起作用。这个时候我们尝试用题目的操作把它们拆开,试图让他们起作用。
也就是每个括号中间分开。翻转交换后得到:1(1 0)10(1 0)010 (为了方便理解我没把括号去掉),这样就多了两个字符起作用,maxlen+2。
而实际上,一次翻转交换操作最多可以使maxlen+2而已,可以理解成一次操作最多能使起作用的字符数+2。(忘了说,maxlen代表原串中最长01子序列的长度)
这样,
我们只需要扫一遍原串,记录maxlen,同时记录是否有连续的0或1,就可以得出答案。
上面的例子是连续的0和1都存在的情况。还有两种情况,一种是只存在连续的0,一种是只存在连续的1,分情况处理就好了。
以下附上通过代码:(不够精简请包涵)
程序代码:
#include <cstdio>
int main(void)
{
int n;
while (~scanf("%d\n", &n))//长度为n
{
char ch_last, ch_first = getchar();//字符串首位和末位,下面的判断需要
int cnt = 1, a = ch_first-'0';
int flag0 = 0, flag1 = 0;//记录字符串中是否有连续的0或1
for (int i=1; i<n; ++i)
{
ch_last = getchar();//逐个字符输入,输入结束时ch_last保存着最后一个字符
a ^= 1;
if (ch_last==a+'0')
cnt++;
else
{
if (!flag0||!flag1)
{
if (a==0) flag1 = 1;
else flag0 = 1;
}
a ^= 1;
}
}
if (flag0&&flag1)//连续的0和连续的1
cnt += 2;
else if (flag0)//只有连续的0
{
if (ch_first-'0'||ch_last-'0')
cnt++;
}
else if (flag1)//只有连续的1
{
if (!(ch_first-'0')||!(ch_last-'0'))
cnt++;
}
printf("%d\n", cnt);
}
return 0;
}