码蹄杯 运动会进行中 题型:模拟 难度:钻石

96 阅读2分钟

码题集OJ-运动会进行中 (matiji.net)

image.png 样例输入:

9
0 1 0 0 0 1 1 0 0

样例输出:

6

思想

我刚开始是这样写的,从两端枚举i,j,这样可以尽快找到满足条件的最大长度段。

每枚举两个端点,我都用前缀和求一下两个端点内的区间和,看一下区间和是否等于总长度的一半(如果该区间1半是1,一半是0,那区间和刚好为长度的一半)。

如果是满足条件的区间,我就存一下该区间的长度。最后在所有合法区间长度中取一个最大长度即是答案。

复杂度方面i,j从左右两端枚举,时间复杂度为O(n),前缀和求区间和复杂度为O(1),总共时间复杂度为O(n)。

但是实际上这样算复杂度是错误的,因为i,j并不是O(n)复杂度,而是O(n^2)。

双指针要求i,j都只遍历一次,总共遍历到n,但是上面的代码针对每个i,j都会全部遍历。

#include<bits/stdc++.h>
using namespace std;
int n ;
const int N=1e5+10;
int a[N],sum[N];
int maxn=-0x3f3f3f3f;
int main()
{
	cin>>n;
	
	for(int i=1;i<=n;i++)cin>>a[i]; 
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];
	
	
	for(int i=1;i<=n;i++)
	{
		for(int j=n;j>=1;j--)
		{
			int Sum=sum[j]-sum[i];
			
		    int Sub=j-i;
		    double t=Sub*1.0/2;
			if((double)Sum==t)
		    {
		    
		    	maxn=max(maxn,j-i);
			}
		}
	}
	cout<<maxn;
	return 0;
}

image.png image.png

正解

看一下官方题解视频再看一下评论区这位老哥的代码就明白了。 image.png

#include<bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
int a[N];
int n;
int cnt, maxlength;
int main()
{
	cin >> n;
	for (int i = 0; i < n; i++)cin >> a[i];

	unordered_map<int, int> count_mp;
	count_mp[0] = -1;

	for (int i = 0; i < n; i++)
	{

		cnt += a[i] ? 1 : -1;


		if (count_mp.find(cnt)!=count_mp.end())
		{
			int previdx = count_mp[cnt];
			int length = i - previdx;
			maxlength = max(maxlength, length);
		}
		else
		{
			count_mp[cnt] = i;
		}
	}

	cout << maxlength;
	return 0;
}

image.png

什么意思呢?就是说我设男为1,女为-1。

假设我前一段区间的和是5,经过一段区间之后的和还是5,说明中间这段区间肯定男女个数相同,给消掉了。

那我就求一下这段区间的长度,最后所有这种情况的长度求一个最大值即可。

image.png