20210810D

19 篇文章 0 订阅
该博客介绍了如何使用二分查找和动态规划算法解决寻找最长相同子序列的问题。第一种方法通过枚举左端点并用二分查找确定右端点,第二种方法则是实时统计0和1的数目,寻找相等的子序列。文章提供了两种不同的代码实现,并对每种方法的时间复杂度进行了分析。
摘要由CSDN通过智能技术生成

题目描述

请添加图片描述

输入

一行整数给出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。

题解:

  1. O ( n log2 n )
  2. 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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值