题目链接:http://codeforces.com/problemset/problem/603/A
题意大概是:给你一个01位串的长度和这个01位串,他想要的是这个串的一个不连续而且任意两个相邻元素都不同的子串的长度,他能对这个位串做一次操作,就是选取其中任意连续的一段(可以选取整个串),然后将它们逐一取反,求他能得到的最大的那个子串长度。
解法参考:http://codeforces.com/blog/entry/21885
由于那个题解是英文的,我来翻译下。
首先,要得到的那个长度,就相当于我们把这个串所有的去掉相邻且重复的元素之后的串的长度,比如,10000011,就转换成101,长度就是3。
至于那个取反的操作,比如我们是对[i,j]里的元素进行了取反操作,这也就相当于,我们先将[0,j]里的元素进行了取反操作,又对[0,i-1]里的元素进行了取反操作(两个前缀字串)。所以这也就相当于我们对这个串进行了两次对它的前缀子串取反的操作。当然,如果i是0的话, 我们就只进行一次。如果i是0,j是n-1的话,相当于进行0次(对所有元素取法取反,我们所求的那个长度值不变,相当于没有进行取反操作)。
所以,我们能进行0或1或2次对它的前缀子串进行取反操作。对它的前缀子串取反,也就相当于对它的另外的那一部分后缀进行取反,所以,我们的取反操作又相当于对[0,i-1]这个前缀子串里的元素取反,再对[j+1,n-1]这个后缀子串里的元素取反,这两个字串不重叠,且他们之间至少相隔一个元素。
这时候,我们去观察我们的前缀子串的最后一个数,如果它与它后面一个数相同,就会使我们要求的那个长度+1,如果相反,会-1,当然,相反的话,我们可以不进行这个取反操作。对于对后缀子串的操作,我们观察后缀子串的第一个数,也有相似的结论。
所以,我们有两次使那个长度+1的机会,只要这个位串有两处以上有连续两个数都相同的地方就行。我们可以先求出初始位串对应的不连续的且相邻不重复的子串的长度。假设初始位串的长度为n,子串的长度为res。如果我们有两处以上有连续两个数都相同的地方,则res<=n-2,所以res+2<=n,如果只有一处,则res+1=n,最终答案是n,如果没有,则最终答案也是n。所以ans=min(res+2,n)。
求解完成。
AC代码:
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring>. #include <algorithm> using namespace std; char str[100005]; int main() { //freopen("input.txt", "r", stdin); int n, res = 1; scanf("%d%s", &n, str); for (int i = 1; i < n; ++i) { if (str[i] != str[i - 1]) ++res; } res = min(res + 2, n); printf("%d\n", res); //system("pause"); //while (1); return 0; }