accoders5124广播操比赛 题解

10.4 国庆集训第一题  传送门

题目描述

XMYZ一年一度的运动会开始了,广播操比赛作为本次活动的第一个集体项目,林老师对此特别重视,经过调查研究,林老师发现当身高接近,而且男女生人数相等时,列队做操是最整齐的。但是按评分的要求,参加的人数越多分数越高,于是林老师想到一个办法:他让年段所有同学按照身高排成一排,然后从中选出连续的若干个人,使得这些人中男女人数相等。根据评分规则,林老师当然希望他能选出的人越多越好。请编写程序告诉他,他最多可以选出多少人来。

输入格式

第一行有一个正整数n,代表年段的人数。

第二行有n个用空格隔开的数,这些数只能是01,其中,0代表一个女生,1代表一个男生

输出格式

输出一个非负整数。这个数表示在输入数据中最长的一段男女人数相等的子序列长度。

如果不存在男女人数相等的子序列,请输出0

样例输入

9

0 1 0 0 0 1 1 0 0

样例输出

6

样例解释

选择第2个人至第7个人可以获得男女人数均为3的最长子序列。

数据范围

对于30%的数据,n100

对于50%的数据,n1 000

对于100%的数据,n100 000

题解

我们仍未知道我的二分错在哪里

这道题网上大多采用dp完成,而前缀和会让代码复杂度减少很多。将女生0改为-1,求序列前缀和f[],如果f[i]=f[j],则说明i+1j前缀和为0,男女生人数相等。

我将前缀和设为数组下标(num[i]=k说明1k是第一段和为i的序列),为避免数组下标为负,将所有前缀和加N。对于ans=n的情况,易知要使num[N](前缀和为0下标为N=0,所以将num数组初值设为-1

AC代码

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define N 100000
using namespace std;
int n,ans=0,a[N+1],f[N+1],num[2*N+1];
int main(){
    memset(num,-1,sizeof(num));           //因为需要把num[N+1]置为0,设初值为-1 
    scanf("%d",&n);
    f[0]=N+1;                           //避免前缀和出现负数导致下标为负 
    for(int i=1;i<=n;i++){               //由于f[i]均由f[i-1]而来,计算时不需要将f[i]+N 
        scanf("%d",&a[i]); 
        if(!a[i]) a[i]--;
        f[i]=f[i-1]+a[i];
    }
    num[N+1]=0;                           //f[i]=1即前缀和为0 
    for(int i=1;i<=n;i++)
        if(num[f[i]]==-1) num[f[i]]=i;  //num[f[i]]等于-1说明此前没有前缀和与f[i]相等 
        else ans=max(ans,i-num[f[i]]);
    printf("%d",ans);
}

 

posted @ 2021-10-04 15:34  key4127  阅读(89)  评论(0)    收藏  举报