题目:在一个n*n的棋盘上,格子标号1~n*n,现在有两个人从1跳到n*n(不走重复点),
现在要求去掉最少的中间点,使得路径是一样的。
分析:dp,LIS,LCS。问题是求最大公共子序列,数据较大需要O(nlgn)算法。
发现题目中的数据是不重复的,所以可以转化成最大上升子序列;
记录序列1中每个元素对应的顺序,将序列2中的元素转化成对应序列1中的顺序标号;
那么,新构成的序列2中递增的序列即为序列1中的先后顺序,所以求出它的LIS即可。
说明:╮(╯▽╰)╭。
#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
using namespace std;
int prince[62505];
int visit[62505];
int princess[62505];
int MUQ[62505];
int lis(int n, int* Q)
{
int l,r,m,i,tail = 0;
for (MUQ[++ tail] = Q[1],i = 2; i <= n; ++ i) {
if (MUQ[tail] < Q[i]) {
MUQ[++ tail] = Q[i];
continue;
}
for (m=((r=tail)+(l=1)>>1); l < r; m=(l+r)>>1)
if (MUQ[m] < Q[i]) l = m+1;
else r = m;
MUQ[m] = Q[i];
}
return tail;
}
int main()
{
int T,n,p,q,k;
while (~scanf("%d",&T))
for (int t = 1; t <= T; ++ t) {
scanf("%d%d%d",&n,&p,&q);
memset(visit, 0, sizeof(visit));
for (int i = 0; i <= p; ++ i) {
scanf("%d",&k);
visit[k] = 1;
prince[k] = i+1;
}
int count = 0;
for (int i = 0; i <= q; ++ i) {
scanf("%d",&k);
if (visit[k])
princess[++ count] = prince[k];
}
printf("Case %d: %d\n",t,lis(count, princess));
}
return 0;
}