uva 10635 - Prince and Princess

开始没想到nlog(n)的解法,不过想到了一种优化o(n^2)的空间复杂度的方法,后来发现网上竟然早就有了,在此不做缀述,o(n^2)超时代码:

#include <iostream>
#include<cstdio>
#include<cstring>
#define N 250*250+5
using namespace std;
int cas=1,n,p,q,t,a[N],b[N],dp[2][N];
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&p,&q);
p++,q++;
for(int i=0;i<p;i++)
scanf("%d",&a[i]);
for(int j=0;j<q;j++)
scanf("%d",&b[j]);
int last=1,ans=1;
for(int j=0;j<n;j++)
dp[0][j]=(a[0]==b[j])?1:0;
for(int i=1;i<p;i++)
{
int k=i%2;
for(int j=0;j<q;j++)
{
if(j==0)
dp[k][j]=1;
else if(a[i]==b[j])
dp[k][j]=dp[1-k][j-1]+1;
else
dp[k][j]=max(dp[k][j-1],dp[1-k][j]);
}
}
printf("Case %d: %d\n",cas++,dp[(p-1)%2][q-1]);
}
return 0;
}

然后果断请教zyz,得到大致的算法思想:将最长公共子串转换为最长上升子序列,但是仍然不知如何去做

后来经过仔细的思考,终于得到如下算法:

//st[i]表示长度为i的公共序列的最小可能位置,s代表答案

 

for(int j=0;j<q;j++)

{

      枚举b[j]在序列a中的每个位置pos

            在数组st中二分查询找到pos的上界

                   更新st数组和s的值

}

巧合的是序列中每个数都是不同的,所以对于此题而言,时间复杂度为nlog(n)

不失一般性,给出这类问题的一般解法:

//最长公共子序列转化为最长上升子串

#include <iostream>

#include<cstdio>

#include<cstring>

#include<algorithm>

#define N 250*250+5

#define INF 1000000000

using namespace std;

int cas=1,n,p,q,t,a[N],b[N],inx[N],st[N],s;

//区间

struct extent

{

    int x,y;

}ext[N];



bool cmp(int x,int y)

{

    if(a[x]!=a[y])

    return a[x]<a[y];

    return x<y;

}

int lower_bound(int v)

{

    int l=0,r=p;

    while(l<r)

    {

        int m=l+(r-l)/2;

        if(a[inx[m]]>=v)

        r=m;

        else

        l=m+1;

    }

    return l;

}

int upper_bound(int v)

{

    int l=0,r=p;

    while(r-l>1)

    {

        int m=l+(r-l)/2;

        if(a[inx[m]]<=v)

        l=m;

        else

        r=m;

    }

    return l;

}

int main()

{

    scanf("%d",&t);

    while(t--)

    {

        scanf("%d%d%d",&n,&p,&q);

        p++,q++;

        for(int i=0;i<p;i++)

        scanf("%d",&a[i]);

        for(int j=0;j<q;j++)

        scanf("%d",&b[j]);

        for(int i=0;i<p;i++)

        inx[i]=i;

        sort(inx,inx+p,cmp);

        for(int i=0;i<q;i++)

        {

            ext[i].x=lower_bound(b[i]);

            ext[i].y=upper_bound(b[i]);

            if(b[i]!=a[inx[ext[i].x]])

            ext[i].x=INF;

        }

        s=1;

        st[1]=0;

        for(int i=1;i<q;i++)

        if(ext[i].x<INF)

        {

            for(int j=ext[i].x;j<=ext[i].y;j++)

            {

                int pos=inx[j];

                if(pos>st[s])

                st[++s]=pos;

                else

                {

                    int l=1,r=s;

                    while(r-l>1)

                    {

                        int m=l+(r-l)/2;

                        if(st[m]<pos)

                        l=m;

                        else

                        r=m;

                    }

                    st[l+1]=pos;

                }

            }

        }

        printf("Case %d: %d\n",cas++,s);

    }

    return 0;

}

  

你可能感兴趣的:(uva)