Description
给出四个长度为 n n n的序列 a , b , c , d a,b,c,d a,b,c,d,求四个序列的最长公共子序列长度
Input
第一行一整数 n n n,之后输入四个长度为 n n n的序列 a , b , c , d a,b,c,d a,b,c,d, a , b , c a,b,c a,b,c三个序列中每种数字出现次数不超过 2 2 2
( 1 ≤ n ≤ 1 0 4 , 1 ≤ a i , b i , c i , d i ≤ n ) (1\le n\le 10^4,1\le a_i,b_i,c_i,d_i\le n) (1≤n≤104,1≤ai,bi,ci,di≤n)
Output
输出四个序列的最长公共子序列长度
Sample Input
5
1 2 1 2 3
1 2 3 1 2
3 1 2 1 2
1 2 1 2 1
Sample Output
4
Solution
由于前三个序列每个数字最多出现两次,那么对于一个 d d d序列中出现的数字, a , b , c a,b,c a,b,c中这个数字的位置组成的三元组情况至多八种,把一个数字在四个序列中出现的位置看作一个四维点对,那么点的数量 m m m不超过 8 n 8n 8n,问题转化为求这 m m m个四维点对的最长严格上升子序列长度,套两层 C D Q CDQ CDQ分治即可,具体操作见代码
注意要严格上升,如果某一维相同,在按这一维排序时,把下一个要考虑的维数降序排,这样就不会出现所求子序列出现某一维相同的情况
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define maxn 80005
struct BIT
{
#define lowbit(x) (x&(-x))
int b[maxn],n;
void init(int _n)
{
n=_n;
for(int i=0;i<=n;i++)b[i]=0;
}
void update(int x,int v)
{
while(x<=n)
{
b[x]=max(b[x],v);
x+=lowbit(x);
}
}
void clear(int x)
{
while(x<=n)
{
b[x]=0;
x+=lowbit(x);
}
}
int query(int x)
{
int ans=0;
while(x)
{
ans=max(b[x],ans);
x-=lowbit(x);
}
return ans;
}
}bit;
struct node
{
int x,y,z,id,flag;
}a[maxn],b[maxn],c[maxn];
bool cmpx(node a,node b)
{
if(a.x!=b.x)return a.x<b.x;
return a.y>b.y;
}
bool cmpy(node a,node b)
{
if(a.y!=b.y)return a.y<b.y;
return a.z>b.z;
}
int n,m,dp[maxn],vis[maxn],pos[maxn][3][2];
void Solve2(int l,int r)
{
if(l==r)return ;
int mid=(l+r)/2;
Solve2(l,mid);
for(int i=l;i<=r;i++)c[i]=b[i];
//游标法
sort(c+l,c+mid+1,cmpy);
sort(c+mid+1,c+r+1,cmpy);
for(int i=l,j=mid+1;j<=r;j++)
{
while(i<=mid&&c[i].y<c[j].y)//保证第二维升序
{
if(c[i].flag==0)bit.update(c[i].z,dp[c[i].id]);
i++;
}
if(c[j].flag==1)//一,二,四维升序,在BIT中查询保证第三维升序
dp[c[j].id]=max(dp[c[j].id],bit.query(c[j].z-1)+1);
}
for(int i=l;i<=mid;i++)
if(c[i].flag==0)bit.clear(c[i].z);
Solve2(mid+1,r);
}
void Solve(int l,int r)
{
if(l==r)return ;
int mid=(l+r)/2;
Solve(l,mid);
for(int i=l;i<=r;i++)b[i]=a[i],b[i].flag=(i>mid?1:0);
sort(b+l,b+r+1,cmpx);//保证第一维升序
Solve2(l,r);
Solve(mid+1,r);
}
int main()
{
scanf("%d",&n);
for(int i=0;i<3;i++)
{
memset(vis,0,sizeof(vis));
for(int j=1;j<=n;j++)
{
int t;
scanf("%d",&t);
if(!vis[t])pos[t][i][0]=pos[t][i][1]=j,vis[t]=1;
else pos[t][i][1]=j;
}
}
m=0;
for(int i=1;i<=n;i++)
{
int t;
scanf("%d",&t);
if(!pos[t][0][0]||!pos[t][1][0]||!pos[t][2][0])continue;
for(int S=7;S>=0;S--)//保证第四维升序,且在第四维相同时第三维是降序的
{
m++;
a[m].id=m;
a[m].x=pos[t][0][S&1];
a[m].y=pos[t][1][S>>1&1];
a[m].z=pos[t][2][S>>2&1];
a[m].flag=0;
dp[m]=1;
}
}
bit.init(n);
Solve(1,m);
int ans=0;
for(int i=1;i<=m;i++)ans=max(ans,dp[i]);
printf("%d\n",ans);
return 0;
}