2017.10.25 DP 解题报告

眼镜(glasses.c/cpp/pas)

3.1 题目描述

这只小动物找到了书中的力量,它几乎就要成功了,依据书中内容,它还缺一副眼镜。
于是它找到了一个01串,想要从中找到制造眼镜的材料。它希望找到这个01串的最长的子序列串(即不要求连续),这个子序列满足01交间的性质(01010…或10101…)。
但是在寻找之前,它想测试一下目前拥有的力量,于是它选择了一段连续的区间,将这个区间中的0变成1、1变成0,再在其中寻找最长01交间子序列串。
当然,它希望合适地运用仅一次自己的力量(但一定要使用),使得这个子序列串变得尽可能长。

3.2 输入格式

仅一行一个长为n的01字符串。

3.3 输出格式

输出一行一个整数表示答案。

3.4 样例输入

10000011

3.5 样例输出

5

3.6 样例解释

将其变为10011011,这个串中的满足条件的子序列串长度即为5,可以证明这是最长的长度。

3.7 数据范围与约定*

对于10%的数据,保证 n<=500。
对于30%的数据,保证 n<=5000。
对于100%的数据,保证n<=500000。

【解题报告】

原本是观察性质直接特判的,想了一个DP
dp[i][3][2]表示已经到了第i为,状态(区间左,区间中,区间右),下一位应该填0还是1

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define N 500010

char s[N];
int n,dp[N][6][2];

int main()
{
    freopen("glasses.in","r",stdin);
    freopen("glasses.out","w",stdout);
    scanf("%s",s+1);n=strlen(s+1);
    memset(dp,-inf,sizeof(dp));
    if(s[1]=='1')
    {
        dp[1][1][0]=1;
        dp[1][2][1]=1;
    }
    if(s[1]=='0')
    {
        dp[1][1][1]=1;
        dp[1][2][0]=1;
    }
    for(int i=2;i<=n;++i)
    {
        if(s[i]=='1')
        {
            dp[i][1][0]=max(dp[i-1][1][0],dp[i-1][1][1]+1);
            dp[i][2][1]=max(dp[i-1][1][1],dp[i-1][1][0]+1);
            dp[i][2][1]=max(dp[i][2][1],max(dp[i-1][2][1],dp[i-1][2][0]+1));
            dp[i][3][0]=max(dp[i-1][2][0],dp[i-1][2][1]+1);
            dp[i][3][0]=max(dp[i][3][0],max(dp[i-1][3][0],dp[i-1][3][1]+1));
        }
        if(s[i]=='0')
        {
            dp[i][1][1]=max(dp[i-1][1][1],dp[i-1][1][0]+1);
            dp[i][2][0]=max(dp[i-1][1][0],dp[i-1][1][1]+1);
            dp[i][2][0]=max(dp[i][2][0],max(dp[i-1][2][0],dp[i-1][2][1]+1));
            dp[i][3][1]=max(dp[i-1][2][1],dp[i-1][2][0]+1);
            dp[i][3][1]=max(dp[i][3][1],max(dp[i-1][3][1],dp[i-1][3][0]+1));        
        }
    }
    int ans=-inf;
    for(int i=2;i<=3;++i)
    for(int j=0;j<=1;++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、付费专栏及课程。

余额充值