codeforces 603A. Alternative Thinking(数学找规律 或者 dp)

题目链接:【A. Alternative Thinking】

输入一串长为n的01串,翻转其中的一段,所谓的翻转就是0变1,1变0,求最终最长01交替的序列长度

样例1:10000011   翻转后得到  10100011   最终的长度就是5  (红色部分)

方法一:数学找规律

原先相邻的变化后仍然相邻,所以我们可以先算出原本就相邻的最长是多少,一个子串翻转后,我们的要求是最长交替01串至少跟原先是一样的,不可能减少,所以一共就只有两种情况

1、相同的数字相邻的总和只有两个  如10010(最初的最长交替串很显然是4)我们想要增加就只能将第三个0改成1,这要引起后边部分的同时改变,不然最终交替串会减少,最后一定是变成10101,长度比原先多了1

2、相同的数字相邻的总和>2(00,11加在一起),那前后已经交替出现的就不要管它了,将相同部分反转,结果必然比原先多2,如:10011=>10101

<span style="font-size:14px;"> #include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
char s[100005];
int main()
{
	int n, a=0, b=0;
	scanf("%d%s", &n, s+1);
	if(s[n]=='0') s[n+1]=1;
	else s[n+1]=0;
	for(int i=1; i<=n; i++)
	{
		if(s[i] == s[i+1]) a++;
		else b++;	
	}
	printf("%d\n", b+min(2, a));
	return 0;
}</span>

方法二:dp

dp[ i ][ j ][ k ]

i表示querylen=i

0<=j<=2,0表示没有翻转,1表示到i为止正在翻转,2表示已经翻转结束

0<=k<=1,0表示位置i是0,1表示位置i是1

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
using namespace std;
const int inf =1e5+10;
char s[inf];
int dp[inf][3][2];
int main()
{
	int n;
	scanf("%d%s", &n, s);
	for(int i=0; i<n; i++)
	{
		for(int j=0; j<3; j++)
		{
			for(int k=0; k<2; k++)
			{
				dp[i+1][j][k] = dp[i][j][k];
			}
		}
		for(int j=0; j<3; j++)
		{
			for(int k=0; k<2; k++)
			{
				int c = s[i]-'0';
				if(k != c)
				{
					dp[i+1][j][c] = max(dp[i+1][j][c], dp[i][j][k]+1);
				}
				else
				{
					if(j < 2)
					{
						dp[i+1][j+1][c] = max(dp[i+1][j+1][c], dp[i][j][c]+1);
					}
				}
			}
		}
	}
	int ans=0;
	for(int i=0; i<3; i++)
	{
		for(int j=0; j<2; j++)
		{
			ans = max(ans, dp[n][i][j]);
		}
	}
	printf("%d\n", ans);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值