51nod 1391 01串(DP)

题目链接
题意:给定一个01串S,求出它的一个尽可能长的子串S[i..j],满足存在一个位置i<=x <=j, S[i..x]中0比1多,而S[x + 1..j]中1比0多。求满足条件的最长子串长度。
初步分析:假设子串S[i..j]是满足条件的一个最长子串,且i和j均不是边界(0<i && j<n-1),则S[i-1]一定是1,否则S[i-1, j]也满足条件且比S[i, j]长,矛盾。同理可推出S[j+1]是0。用类似的逻辑进一步可推出存在一个位置i<=x <=j, S[i..x]中0比1恰好多1个,而S[x + 1..j]中1比0恰好多1个。把原数组中所有的0用-1代替,子串01个数的比较就可以转换为子串和的正负。
思路:先处理i和j不是边界的情况,根据上面的初步分析,可以枚举x,然后分别考虑到x结尾的和为-1的最长子串的长度,以x+1开头的和为1的最长子串的长度。这两个子问题都可以通过hash来解决(类似于求最长01子串,使得0和1个数相等)。i,j是边界的情况特殊处理就好。
代码虽然写得挫,还是忍不住贴一个:

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 11;
char s[N];
int a[N];
int pre[N], suf[N];
int start[N], end[N];
int f[2*N];
int main()
{
    freopen("in.txt", "r", stdin);
    while(1==scanf("%s", s+1)){
        int n = strlen(s+1);
        for(int i=1; i<=n; i++){
            a[i] = s[i]==‘1‘ ? 1 : -1;
        }
        memset(f, 0x3f, sizeof(f));
        memset(end, 0, sizeof(end));
        pre[0] = 0;
        for(int i=1; i<=n; i++){
            pre[i] = pre[i-1] + a[i];
            int tmp = pre[i] + N;
            end[i] = max(0, i - f[tmp+1]);
            f[tmp] = min(f[tmp], i);
        }
        memset(f, 0, sizeof(f));
        memset(start, 0, sizeof(start));
        suf[n+1] = 0;
        for(int i=n; i>=1; i--){
            suf[i] = suf[i+1] + a[i];
            int tmp = suf[i] + N;
            start[i] = max(0, f[tmp-1] - i);
            f[tmp] = max(f[tmp], i);
        }
        int ans = 0;
        for(int i=1; i<=n; i++){
            if(pre[i]<0 && suf[i+1]>0)    ans = n;
        }
        for(int i=1; i<=n; i++){
            if(pre[i]<0 && start[i+1]>0){
                ans = max(ans, i+start[i+1]);
            }
        }
        for(int i=n; i>=1; i--){
            if(suf[i]>0 && end[i-1]>0){
                ans = max(ans, n+1-i + end[i-1]);
            }
        }
        for(int i=1; i<=n; i++){
            if(end[i]>0 && start[i+1]>0){
                ans = max(ans, end[i]+start[i+1]);
            }
        }
        printf("%d\n", ans);
    }
    return 0;
}

时间: 2024-08-03 23:38:59

51nod 1391 01串(DP)的相关文章

51nod 1391 01串(锻炼思维的好题)

题目http://www.51nod.com/onlineJudge/questionCode.html#problemId=1391?iceId=20917 1391 01串 题目来源: Codility 基准时间限制:1 秒 空间限制:131072 KB 分值: 40 难度:4级算法题 给定一个01串S,求出它的一个尽可能长的子串S[i..j],满足存在一个位置i<=x <=j, S[i..x]中0比1多,而S[x + 1..j]中1比0多.求满足条件的最长子串长度. Input 一行包含

51nod——1391 01串(字符串、前缀和)

好像这题是4级题下放2级? 预处理:求每个位置 x 左区间 [ 0 , x ] 中 1 比 0 多的数量和右区间 ( x , n - 1 ] 中 0 比 1 多的数量(少就是负的).相当于求两个前缀和.这样在判断 1 多还是 0 多时判断前缀和与零的大小关系就行了. 更新答案:对于字符串中的每个位置 x 的左侧,要求前缀和小于零.如果小于零,符合要求,长度即下标加一.如果大于零(设为 k ),要从头开始,找到第一个位置,这个位置的左侧 1 也比 0 多 k 个,这样把这个位置之前的串剪掉,就剩下

51nod 还是01串

给定一个0-1串s,长度为n,下标从0开始,求一个位置k,满足0<=k<=n, 并且子串s[0..k - 1]中的0的个数与子串s[k..n - 1]中1的个数相等. 注意: (1) 如果k = 0, s[0..k - 1]视为空串 (2) 如果k = n, s[k..n - 1]视为空串 (3) 如果存在多个k值,输处任何一个都可以 (4) 如果不存在这样的k值,请输出-1 想了一会,发现没有-1的情况的,就是个坑,假设0- k-1有x个1,k,n-1有y个1,那么0- k-1有k-x个0,

nyoj 01串 (DP)

01串 时间限制:1000 ms  |  内存限制:65535 KB 难度:2 描述 ACM的zyc在研究01串,他知道某一01串的长度,但他想知道不含有"11"子串的这种长度的01串共有多少个,他希望你能帮帮他. 注:01串的长度为2时,有3种:00,01,10. 输入 第一行有一个整数n(0<n<=100),表示有n组测试数据; 随后有n行,每行有一个整数m(2<=m<=40),表示01串的长度; 输出 输出不含有"11"子串的这种长度的

AC日记——还是01串 51nod 1396

还是01串 思路: 前缀和: 来,上代码: #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define maxn 1000005 int n,sum[maxn]; char ch[maxn]; int main() { gets(ch),n=strlen(ch); for(int i=0;i<n;i+

01串也疯狂之光棍也有伴

Description 话说春节那天,小明和晓明在实验室刷题.刷着刷着小明觉得累了,就邀请晓明一起看春晚.晓明觉得小明很无聊,不想理小明,但是小明很会磨嘴皮子,晓明耐不住小明的胡嘴蛮缠,于是和小明一起看起春晚来. 小明顿时觉得倍儿爽啊! 可是一看,“wocao”,“最炫小苹果”,小明顿时觉得很伤心. “连小苹果都有伴了...呜呜....” 晓明看到小明哭了,就想安慰他,可是怎么安慰呢!  晓明陷入了沉思,忽然,晓明灵光一闪,想借一下出题名义,让小明开心起来.于是晓明对小明说,既然小苹果都有伴了,

01串 ---- 递推

这是一个符合斐波纳契数列的dp问题,动态转移方程:dp[i]=dp[i-1]+dp[i-2]; 解释:长度为i的01串组成:长度为i-1的串末尾的0的个数*2+长度为i-1的串末尾的1的个数*1,而长度为i-1的末尾的0的个数等于长度为i-2的串的个数,等量替换以后就是上面的转移方程. 1 #include<stdio.h> 2 #include<string.h> 3 #include<math.h> 4 #include<iostream> 5 #inc

GDUT 初赛 01串也疯狂之光棍也有伴

Problem A: 01串也疯狂之光棍也有伴 Description 话说春节那天,小明和晓明在实验室刷题.刷着刷着小明觉得累了,就邀请晓明一起看春晚.晓明觉得小明很无聊,不想理小明,但是小明很会磨嘴皮子,晓明耐不住小明的胡嘴蛮缠,于是和小明一起看起春晚来. 小明顿时觉得倍儿爽啊! 可是一看,"wocao","最炫小苹果",小明顿时觉得很伤心. "连小苹果都有伴了...呜呜...." 晓明看到小明哭了,就想安慰他,可是怎么安慰呢! 晓明陷入了沉

USACO Training3.2 01串 By cellur925

题目传送门 一句话题意:求长度为n的有m个1的大小为第k个的01串. 暑假我做的时候是真·大暴力,用二进制枚举,55分,成功T掉无数点. 正解:开始可以用计数类dp来"预处理",状态和转移都比较好想. 状态:设f[i][j]表示i位二进制数,1的个数不超过j的种类数. 转移:f[i][j]=f[i-1][j]+f[i-1][j-1] (当前位取0或1) 初值:f[i][0]=0,f[0][i]=0; 然后?我们尝试倒序枚举答案.我们知道在二进制中最高位为1时一定比最高位为0的情况大,所