【挖坑记】JZOJ 4721 最长公共子序列

题目大意

给出长度为n,m的序列a,b,求出最长公共子序列
n,m<=300000
时间限制1s
空间限制256M

解题思路

先离散化,把b[i]在序列a中出现的位置pos[i]求出来,然后求一个最长上升子序列。

#include
#include
#include
#define maxn 300006
#define fr(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;

struct nod
{
    int x,y,z;
} d[maxn+maxn];
bool cmp(nod a,nod b)
{
    return a.xx;
}
int i,n,m,s,tot,ans,a[maxn],b[maxn],pos[maxn],f[maxn],tr[maxn*4];
void modify(int v,int st,int en,int x,int y)
{
    if (st==en)
    {
        tr[v]=y;
        return;
    }
    int m=(st+en) >> 1;
    if (x<=m) modify(v+v,st,m,x,y);
    else modify(v+v+1,m+1,en,x,y);
    tr[v]=max(tr[v+v],tr[v+v+1]);
    return;
}
void findd(int v,int st,int en,int l,int r)
{
    if (st==l && en==r)
    {
        s=max(s,tr[v]);
        return;
    }
    int m=(st+en) >> 1;
    if (r<=m) findd(v+v,st,m,l,r);
    else if (l>m) findd(v+v+1,m+1,en,l,r);
    else
    {
        findd(v+v,st,m,l,m);
        findd(v+v+1,m+1,en,m+1,r);
    }
    return;
}
int main()
{
    scanf("%d%d",&n,&m);
    fr(i,1,n) 
    {
        scanf("%d",&a[i]);
        d[i].x=a[i],d[i].y=i,d[i].z=1;
    }
    fr(i,1,m)
    {
        scanf("%d",&b[i]);
        d[n+i].x=b[i],d[n+i].y=i,d[n+i].z=2;
    }
    sort(d+1,d+n+m+1,cmp);
    int k=0;
    d[0].x=1 << 30;
    fr(i,1,n+m)
    {
        if (d[i].x!=d[i-1].x) ++k;
        if (d[i].z==1) a[d[i].y]=k;
        else b[d[i].y]=k;
    }
    fr(i,1,n) pos[a[i]]=i;
    fr(i,1,m) b[i]=pos[b[i]];
    fr(i,1,m)
    {
        s=0;
        if (b[i]) findd(1,0,m,0,b[i]-1);
        else continue;
        f[i]=s+1;
        modify(1,0,m,b[i],f[i]);
        ans=max(ans,f[i]);
    }
    printf("%d\n",ans);
    return 0;
}

你可能感兴趣的:(挖坑记)