2014.10.4模擬賽【球的序列】

球的序列(formation.*)

   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

題意就是給你兩個1~n的排列,求最長公共子序列

n^2顯然dp隨便寫

但是n是5w級別,所以不能這樣搞

考慮到這題特殊之處在於是兩個1~n的排列,我們可以把它轉換成求最長上升子序列的問題

對於原來的最長公共子序列,要求元素在a數組中的位置是遞增的,在b數組中也是遞增的

那麼我們考慮用s[i]表示b[i]在a數組中的位置

那麼在s數組中取下標遞增的子序列,在原來的b數組中也是遞增的

如果我們再在s中取大小遞增的子序列,在原來的a數組中也是遞增的(很簡單,不會自己yy一下)

所以變成在s數組中做最長上升子序列,這個nlogn就搞定了

當時我就A掉了它

#include<cstdio>
#include<iostream>
#include<algorithm>
#define N 100010
using namespace std;
int pos[N];
int a[N];
int mn[N];
int n,mx;
inline int search(int x)
{
	int l=1,r=mx;
	int s=0;
	while (l<=r)
	{
		int mid=(l+r)>>1;
		if (mn[mid]<x){s=mid;l=mid+1;}
		else r=mid-1;
	}
	return s;
}
int main()
{
	freopen("formation.in","r",stdin);
	freopen("formation.out","w",stdout);
	scanf("%d",&n);
	for (int i=1;i<=n;i++)
	{
		int x;scanf("%d",&x);
		pos[x]=i;
	}
	for (int i=1;i<=n;i++)
	{
		int x;scanf("%d",&x);
		a[i]=pos[x];
	}
	mn[1]=a[1];mx=1;
	for (int i=2;i<=n;i++)
	 {
	 	int find=search(a[i]);
	 	if (find==mx)mn[++mx]=a[i];
	 	else if (mn[find+1]>a[i])mn[find+1]=a[i];
	 }
	printf("%d\n",mx);
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章