题目描述
N个编号为1-n的球,每个球都有唯一的编号。这些球被排成两种序列,分别为A、B序列,现在需要重新寻找一个球的序列l,对于这个子序列l中任意的两个球,要求j,k(j<k),都要求满足lj在A中位置比lk在A中位置靠前,且lj在B中位置比lk在B中位置靠前,请你计算这个子序列l的最大长度。
输入:
第一行一个整数,表示N。
第二行N个整数,表示A序列。
第三行N个整数,表示B序列。
样例输入
5
1 2 4 3 5
5 2 3 4 1
样例输出
2
样例说明
L可以是{2,3},也可以是{2,4}
数据范围:
40% N<=5000
100% N<=50000
题解
画个图就知道是LIS了。nlogn的做法经典。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define ll long long
using namespace std;
int n,loc[50002],a[50002];
int f[50002],s[50002],l,r,ans;
void init()
{
scanf("%d",&n);
int i,x;
for(i=1;i<=n;i++)
{scanf("%d",&x);
loc[x]=i;
}
for(i=1;i<=n;i++)
{scanf("%d",&x);
a[i]=loc[x];
}
}
int erf(int x)
{
int b=l,e=r,mid,w=0;
while(b<=e)
{mid=(b+e)>>1;
if(s[mid]<x) {w=mid; b=mid+1;}
else e=mid-1;
}
return w;
}
void dp()
{
memset(s,127,sizeof(s));
f[1]=1; s[1]=a[1]; l=1; r=1; ans=1;
int i,w;
for(i=2;i<=n;i++)
{w=erf(a[i]);
f[i]=w+1; ans=max(ans,f[i]);
s[w+1]=min(s[w+1],a[i]);
if(w==r) r++;
}
printf("%d\n",ans);
}
int main()
{
freopen("formation.in","r",stdin);
freopen("formation.out","w",stdout);
init(); dp();
return 0;
}