uva10635Prince and Princess(LIS)

题意:求最长相同公共子序列。

分析:《训练指南》P66,本题是一道经典的题目,巧妙的将LCS问题转化为LIS问题。这种题目的一个特定就是其中一个序列的所有元素均不相同。首先,我们可以对A数组重新编号为{1,2,3,...n},接下来对于B数组的每个元素,替换为A中那个元素的编号,若没有在A中出现,那么直接置0,这样,B数组也变为一个由编号构成的数组,此时我们发现,A数组是一个自然序列,那么只要在B中找到最长上升的子序列,就是和A的最长公共子序列!这就是本题的巧妙之处!而LIS问题有O(N*logN)的解法,因此可以通过本题的数据规模。

为什么呢?

A'中为A中元素的代号 即 它们的顺序号

B'中为B中元素对应的代号(为了分析方便,这里将B中有而A中没有出现的去掉,等价于置0)

因为去掉了B中有而A中没有出现的,所以B'中的代号全部对应A中的数

设B'的一个子集p,那么将p由代号翻译成原来数字后一定是A的一个子集(不过在A中顺序不确定)

B'的LIS时B‘中一个上升的子集即顺序号上升的子集 即 该子集在A中是按从左到右的顺序的

所以它是A与B的公共子序列

又因为LIS最长,所以公共子序列最长即最长公共子序列

参考:https://www.cnblogs.com/FuTaimeng/p/5410465.html。

代码:

#include<bits/stdc++.h>
using namespace std;

const int maxn = 250 * 250;
const int INF = 1000000000;
int S[maxn], g[maxn], d[maxn]; // LIS所需
int num[maxn]; // num[x]为整数x的新编号,num[x]=0表示x没有在A中出现过

int main() {
  int T;
  scanf("%d", &T);
  for(int kase = 1; kase <= T; kase++) {
    int N, p, q, x;
    scanf("%d%d%d", &N, &p, &q);
    memset(num, 0, sizeof(num));
    for(int i = 1; i <= p+1; i++) { scanf("%d", &x); num[x] = i; }
    int n = 0;
    for(int i = 0; i < q+1; i++) { scanf("%d", &x); if(num[x]) S[n++] = num[x]; }

    // 求解S[0]...S[n-1]的LIS
    for(int i = 1; i <= n; i++) g[i] = INF;
    int ans = 0;
    for(int i = 0; i < n; i++) {
      int k = lower_bound(g+1, g+n+1, S[i]) - g; // 在g[1]~g[n]中查找
      d[i] = k;
      g[k] = S[i];
      ans = max(ans, d[i]);
    }
    printf("Case %d: %d\n", kase, ans);
  }
  return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值