题目描述
输入
一行整数给出n
第二行给出序列a,ai=0表示男生,ai=1表示女生
输出
最大长度
输入样例
9
0 1 0 0 0 1 1 0 0
输出样例
6
说明
30%的数据,n<=100。
50%的数据,n<=1000。
100%的数据,n<=100000。
题解:
- O ( n log2 n )
- O ( n )
方法一:
枚举左端点,二分查询右端点
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned LL
#define db double
#define ldb long db
#define re register
using namespace std;
const int N=1e7+100,M=2020;
struct sb
{
int x,wz;
} s[N];
int n,to=2,ans,a[N];
bool cmp ( sb a,sb b ) { return a.x==b.x?a.wz>b.wz:a.x<b.x; }
int find ( int wz,int ans )
{
int l=1,r=n;
while ( l<r )
{
int mid=( l+r )>>1;
if ( s[mid].x>=ans ) r=mid;
else l=mid+1;
}
if ( s[l].wz>=wz ) return s[l].wz;
return -1;
}
int find ( int wz )
{
int num=2*a[wz-1]+1-wz;
return find ( wz,num );
}
int main ( )
{
scanf ( "%d",&n );
for ( int i=1;i<=n;i++ ) scanf ( "%d",&a[i] ),a[i]+=a[i-1],s[i].x=a[i]*2-i,s[i].wz=i;
sort ( s+1,s+1+n,cmp );
for ( int i=1;i<=n;i++ )
{
if ( i+ans-1>n ) break;
to=find ( i );
ans=max ( ans,to-i+1 );
}
printf ( "%d",ans%2?0:ans );
return 0;
}
有点麻烦
so…………
方法二:
当当前数是 1 则统计加一,当当前数是 0 则统计减一
则一段 0 1 相等的数列,总和为零,表现在数列上就是前后两次统计相等
如样例:
9
0 1 0 0 0 1 1 0 0
统计为:
-1 0 -1 -2 -3 -2 -1 -2 -3
—— —— ^^ == ^^ —— ^^ ==
三中相等 —— ^^ ==
再加上一个小技巧,a [ i ] 为 i 这个数最早出现的位置
Code
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#define LL long long
#define ull unsigned LL
#define db double
#define ldb long db
#define re register
using namespace std;
const int N=1e6+100,M=2020;
int n,x,ans=1e5*2,maxn,a[N*2];
int main ( )
{
scanf ( "%d",&n );
memset ( a,-1,sizeof ( a ) );
a[ans]=0;
for ( int i=1;i<=n;i++ )
{
scanf ( "%d",&x );
ans+=x?1:-1;
if ( a[ans]!=-1 ) maxn=max ( maxn,i-a[ans] );
else a[ans]=i;
}
printf ( "%d",maxn );
return 0;
}