UVA - 10635 Prince and Princess

69 篇文章 0 订阅
27 篇文章 0 订阅

好题,一道题目复习了多个知识点

首先一看就是lcs,可以用n*n的dp来做,但一看数据量,n可以到10000,虽然空间可以优化,但绝对要超时。于是就只能先把lcs 转化成lis再用nlgn的算法求出来。

首先,将lcs转化成lis:

将s1中的数字在s2中出现的位置记下来并由大到小排列,然后用排列后的数组替换s1中该数字出现的所有位置,这题各个数字都是不同的,所以做着非常方便,注意如果数字重复很多,这样就可能退化成n*n的。这样做可行的原理就是,将对应的位置存下来之后,只要是s1中的数字,在s2中都有对应,且对于现在的s1来说,这些数字对应的原来的数字的出现顺序是上升的,然后只要求这些数字的lis,就得到了对应于s2的序列,且这个子序列在s2中也是按位置上升的,于是对应的序列刚好就是lcs。

然后nlgn lis求法:

用s1中的元素维护一个栈,先使栈中的元素构成递增序列,这时,栈的大小就是该递增序列的长度,牢记这一点,栈的大小是递增序列的长度且我们只关心它的长度而不关心内容。然后依次遍历s1中的元素,如果元素比栈顶元素大,直接入栈,这个很好理解;如果小于栈顶元素,就到栈中二分查找大于它的第一个元素,并替换掉,这时,栈中的递增系列虽然不是原s1中的lis,但栈的大小依然是刚才得到的最大的递增序列的长度,只是插入的这个元素,为将来可能更长的lis做好了准备。

最后就是二分查找的写法,注意mid=front+(rear-front)/2搭配front<rear和front=mid+1,相对来说比较简洁

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#define MAX 63000
using namespace std;

int n,p,q,s[MAX],s1[MAX],s2[MAX],mapt[MAX],stackt[MAX],indext,sp;

int bs(int value){
    int frontt=0,rear=sp;
    while(frontt<rear){
        int mid=frontt+(rear-frontt)/2;
        if(stackt[mid]<value)
            frontt=mid+1;
        else
            rear=mid;
    }
    return frontt;
}

int findt(){
    sp=0;
    for(int i=0;i<indext;i++){
        if(sp==0||sp>0&&s[i]>stackt[sp-1])
            stackt[sp++]=s[i];
        else if(s[i]<stackt[sp-1]){
            int ret=bs(s[i]);
            stackt[ret]=s[i];
        }
    }
    return sp;
}

int main(){
    int T,cases=0;
    cin>>T;
    while(T--){
        memset(mapt,-1,sizeof(mapt));
        indext=0;
        cin>>n>>p>>q;
        for(int i=0;i<=p;i++){
            cin>>s1[i];
            mapt[s1[i]]=i;
        }
        for(int i=0;i<=q;i++){
            cin>>s2[i];
            if(mapt[s2[i]]!=-1)
                s[indext++]=mapt[s2[i]];
        }
        cout<<"Case "<<++cases<<": "<<findt()<<endl;
    }
    return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值