2019牛客暑期多校赛(第三场)B-求01串中的最长01数量相等的子串和子序列

https://ac.nowcoder.com/acm/contest/883/B

首先先把0所在的位置变-1,1所在位置变1,然后统计一个前缀和,用sum[i]表示。

那么如果从起点开始的话只要满足条件的子串那么sum[i]的值就是0

如果子串起点不为0,那么只要以前出现过sum[i]的值,这两个值之间的串就一定是合法的子串。

例如:

标号:1  2  3  4  5 

数值:0  0  1  1  0

sum:-1 -2 -1 0 -1

i==4的时候sum[i]==0,所以1-5间合法,长度是4

而sum[1]==sum[3]==sum[5]==-1,所以第一次出现-1的位置是1,而最后出现的位置是5,所以其中长度5-1=4也是一个合法的区间子串。

子序列就很简单了,只要求0,1的个数取最小数量乘2

#include<bits/stdc++.h>
using namespace std;
typedef long long int ll;
typedef unsigned long long int ull;
const int inf = 0x3f3f3f3f;
int dir[8][2]={{1,0},{0,1},{1,1},{1,-1},{-1,1},{-1,-1},{0,-1},{-1,0}};
#define pi acos(-1)
#define ls rt<<1
#define rs rt<<1|1
#define me0(s) memset(s,0,sizeof(s))
#define me1(s) memset(s,1,sizeof(s))
#define mef(s) memset(s,-1,sizeof(s))
#define meinf(s) memset(s,inf,sizeof(s))
const int N=100005;
int sum[N],t[N];
inline int read() {
    char c=getchar(); int x=0, f=1;
    while(c<'0'|c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
    return x*f;
}
ll exgcd(ll a,ll b){
    if(b==0) return a;
    exgcd(b,a%b);
}
ll q_pow(ll a,ll b,ll mod){
    ll anss=1;
    while(b){
        if(b&1) anss=anss*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return anss;
}
ll q_mul(ll a,ll b,ll mod){
    ll anss=0;
    while(b){
        if(b&1) anss=(anss+a)%mod;
        a=(a+a)%mod;
        b>>=1;
    }
    return anss;
}
int main(int argc, char * argv[]) 
{
    std::ios::sync_with_stdio(false);
    int n,l2=0,y2=0,ans2,v[N];
    mef(v);
    char s[N];
    cin>>n;
    cin>>s+1;
    int len=strlen(s+1);
    for(int i=1;i<=len;i++){
        if(s[i]=='1'){
            t[i]=1;
            y2++;
        }
        else{
            t[i]=-1;
            l2++;
        }
    }
    sum[1]=t[1];
    map<int,int>m;
    m[sum[1]]=1;
    int maxn=0;
    for(int i=2;i<=len;i++){
        sum[i]=sum[i-1]+t[i];  //算出sum
        if(m[sum[i]]!=0) maxn=max(maxn,i-m[sum[i]]);//如果出现过以前的sum值,则当前的位置减第一次的位置
        else m[sum[i]]=i;//否则记录第一个出现的sum值的位置
        if(sum[i]==0) maxn=max(maxn,i);//为0表示前面所有的01相等
//        cout<<sum[i]<<" "<<m[sum[i]]<<endl;
    }
    ans2=2*(l2>y2?y2:l2);
    cout<<maxn<<" "<<ans2<<endl;
    return 0;
}

 

posted @ 2019-07-25 13:35  wushuyng  阅读(482)  评论(0编辑  收藏  举报