• 2019牛客多校训练第三场B.Crazy Binary String(思维+前缀和)


    题目传送门

    大致题意:

    输入整数n(1<=n<=100000),再输入由n个0或1组成的字符串,求该字符串中满足1和0个数相等的最长子串、子序列。

    sample input:

    8
    01001001

    sample output:

    4 6

    题解:

    补充一下子串和子序列的区别:字串必须连续,子序列不必连续。

    求01个数相等的最长子序列长度:min(0的个数,1的个数)。

    下面说求01个数相等的最长子串长度:

    可以建一个sum数组求前缀和,因为要使0和1个数相等,所以0可以用-1代替,故当sum[r]-sum[l-1]=0时区间[l,r]则为满足01个数相等的子串,此时求出l-1和r的差值即为满足条件的子串长度,不断更新结果求最大长度。

    但是到这一步后起初想到的做法是两重循环枚举更新最大差值,这样会超时。

    O(n)做法:建一个flag数组记录不同前缀和第一次出现的下标位置(也可用map记录),后面找到相同前缀和时则更新两者位置的差值,这样扫一遍就可以了。(注意:当前缀和sum[r]=0时,r即为满足条件的子串长度)

    官方题解如下:

    Code:

     1 /*5ms*/
     2 #include<bits/stdc++.h>
     3 #define IO ios::sync_with_stdio(false);
     4 using namespace std;
     5 const int MAX=1e5+5;
     6 char s[MAX];
     7 int n,sum[MAX],flag[2*MAX],max1;
     8 int main()
     9 {
    10     IO;
    11     while(!(cin>>n>>s+1).eof())
    12     {
    13         memset(flag,-1,sizeof(flag));
    14         int ans1=0,ans0=0;
    15         for(int i=1;i<=n;i++){
    16             if(s[i]=='0')ans0++,sum[i]=sum[i-1]-1;
    17             else ans1++,sum[i]=sum[i-1]+1;
    18             if(flag[MAX+sum[i]]==-1)flag[MAX+sum[i]]=i;
    19             else max1=max(i-flag[MAX+sum[i]],max1);
    20             if(sum[i]==0)max1=max(max1,i);
    21         }
    22         cout<<max1<<' '<<2*min(ans1,ans0)<<endl;
    23     }
    24     return 0;
    25 }

    或者用STL的map实现,代码如下:

     1 /*52ms*/
     2 #include<bits/stdc++.h>
     3 #define IO ios::sync_with_stdio(false);
     4 using namespace std;
     5 map<int,int>m;
     6 int main()
     7 {
     8     IO;char c;int n;
     9     while(!(cin>>n).eof())
    10     {
    11         int ret=0,ans1=0,sum=0;
    12         m.clear();m[0]=0;
    13         for(int i=1;i<=n;++i){
    14             cin>>c;
    15             if(c=='1')ans1++,sum++;
    16             else sum--;
    17             if(m.count(sum))ret=max(ret,i-m[sum]);//map.count(Key)返回值为1或者0,1返回存在,0返回不存在
    18             else m[sum]=i;
    19         }
    20         cout<<ret<<' '<<2*min(ans1,n-ans1)<<endl;
    21     }
    22     return 0;
    23 }
  • 相关阅读:
    winform combobox SelectedText值为空
    【转】C#、面向对象、设计模式学习
    oracle查询分区表中的数据
    ORA-14402:更新分区关键字列将导致分区更改
    winform列标题高度无法改变
    【转】c#中@的3种作用
    winform 弹出的form显示在最前端
    winform datagridview数据显示不全
    【转】如何把CD上的音乐拷贝到电脑上
    开关WIFI脚本
  • 原文地址:https://www.cnblogs.com/HOLLAY/p/11256868.html
Copyright © 2020-2023  润新知