accoders5124广播操比赛 题解
10.4 国庆集训第一题 传送门
题目描述
XMYZ一年一度的运动会开始了,广播操比赛作为本次活动的第一个集体项目,林老师对此特别重视,经过调查研究,林老师发现当身高接近,而且男女生人数相等时,列队做操是最整齐的。但是按评分的要求,参加的人数越多分数越高,于是林老师想到一个办法:他让年段所有同学按照身高排成一排,然后从中选出连续的若干个人,使得这些人中男女人数相等。根据评分规则,林老师当然希望他能选出的人越多越好。请编写程序告诉他,他最多可以选出多少人来。
输入格式
第一行有一个正整数n,代表年段的人数。
第二行有n个用空格隔开的数,这些数只能是0或1,其中,0代表一个女生,1代表一个男生。
输出格式
输出一个非负整数。这个数表示在输入数据中最长的一段男女人数相等的子序列长度。
如果不存在男女人数相等的子序列,请输出0。
样例输入
9
0 1 0 0 0 1 1 0 0
样例输出
6
样例解释
选择第2个人至第7个人可以获得男女人数均为3的最长子序列。
数据范围
对于30%的数据,n≤100;
对于50%的数据,n≤1 000;
对于100%的数据,n≤100 000。
题解
我们仍未知道我的二分错在哪里
这道题网上大多采用dp完成,而前缀和会让代码复杂度减少很多。将女生0改为-1,求序列前缀和f[],如果f[i]=f[j],则说明i+1到j前缀和为0,男女生人数相等。
我将前缀和设为数组下标(num[i]=k说明1到k是第一段和为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); }