https://vjudge.net/contest/221630#problem/D
这个题目是公主和王子都从(0,0)走到(n,n),只不过路径不完全相同,让你找出两人的最大可以共同走过的地方。
Sample Input
1
3 6 7
1 7 5 4 8 3 9
1 4 3 5 6 2 8 9
Sample Output
Case 1: 4
解题思路:
这个题其实是其最长公共子串问题,但是因为题目是255*255的,如果按照LCS算法进行得话,时间复杂度为(255*255)^2,会超时,所以改成求最大上升子序列。
数列a和数列b
将数列b中的数按其在数列a中出现的顺序重新编号,a中没有的则不记录
如a: 1 7 5 4 8 3 9
b: 1 4 3 5 6 2 8 9 重新编号后: 0 3 6 2 4 6
然后求b的最长上升子序列。因为求最长上升子序列的时间复杂度依然为n^2,但是可以改进,使用二分法来求第一个大于num的下标,故可以将时间复杂度减小为(nlogn)。
dp[n]始终保持上升子列长度为n的最后一位数(越小越好)保持最小值。
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
int num[255*255],bnum[255*255],dp[255*255];
int n,p,q;
int find(int i,int j,int num){//二分法找到dp[]中第一个大于num的那个数的下标
while(i<j){
int mid=(i+j)/2;
if(dp[mid]>num) j=mid;
else i=mid+1;
}
return j;
}
int main(){
int t;
cin>>t;
int tt=0;
while(t--){
tt++;
cin>>n>>p>>q;
int sa,sb;
memset(num,-1,sizeof(num));
memset(bnum,0,sizeof(bnum));
memset(dp,0,sizeof(dp));
for(int i=0;i<=p;i++){
cin>>sa;
num[sa]=i;
}
int m=0;
for(int i=0;i<=q;i++){
cin>>sb;
if(num[sb]!=-1)
bnum[m++]=num[sb];
}
dp[1]=bnum[0];
int k=1,mid;
for(int i=1;i<m;i++){
if(bnum[i]>dp[k]) dp[++k]=bnum[i];
else{
mid=find(0,k,bnum[i]);
dp[mid]=bnum[i];
}
}
printf("Case %d: %d\n",tt,k);
}
return 0;
}