zoukankan      html  css  js  c++  java
  • 51nod 1391 01串(hash+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
    ", ans);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    hdu 4849
    HDU4850 构造一个长度为n的串,要求任意长度为4的子串不相同
    2014 多校第一场官方题解。
    hdu4862 2014多校B题/ 费用流(最优情况下用不大于K条路径覆盖)(不同的解法)
    dp+分类讨论 Gym 101128E
    优先队列 逆向思维 Gym 101128C
    很好的脑洞题:dfs+暴力 Gym
    树dp...吧 ZOJ 3949
    扫描线(线段树)+贪心 ZOJ 3953
    dp ZOJ 3956
  • 原文地址:https://www.cnblogs.com/algorithms/p/4731399.html
Copyright © 2011-2022 走看看