【挖坑記】JZOJ 4721 最長公共子序列

題目大意

給出長度爲n,m的序列a,b,求出最長公共子序列
n,m<=300000
時間限制1s
空間限制256M

解題思路

先離散化,把b[i]在序列a中出現的位置pos[i]求出來,然後求一個最長上升子序列。

#include<cstdio>
#include<cstring>
#include<algorithm>
#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.x<b.x;
}
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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章