最长上升子序列
Description
LIS问题是最经典的动态规划基础问题之一。
如果要求一个满足一定条件的最长上升子序列,你还能解决吗?
给出一个长度为
N
整数序列,请求出它的包含第
例如:对于长度为
6
的序列
Input
第一行为两个整数
N
,
接下来是
N
个整数,描述一个序列。
Output
请输出两个整数,即包含第
Sample Input
8 6
65 158 170 299 300 155 207 389
Sample Output
4
Solution
去除第 k <script type="math/tex" id="MathJax-Element-85">k</script> 个元素前面比它大的所有元素,去除其后面所有比它小的元素,求LIS即可。
Code
#include <iostream>
#include <cstdio>
using namespace std;
int n,k,top=0;
int s[200010],xu[200010]={-0x3f3f3f3f};
bool can[200010];
int search(int l,int r,int x){
int pos=0;
while(l<=r){
int mid=(l+r)>>1;
if(xu[mid]<x){
pos=mid;
if(l!=mid+1)l=mid+1;
else break;
}
else{
if(r!=mid-1)r=mid-1;
else break;
}
}
return pos;
}
int main(){
freopen("lis.in","r",stdin);
freopen("lis.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)scanf("%d",&s[i]);
for(int i=1;i<k;i++)if(s[i]>s[k])can[i]=true;
for(int i=k+1;i<=n;i++)if(s[k]>s[i])can[i]=true;
for(int i=1;i<=n;i++)if(!can[i]){
if(s[i]>xu[top])xu[++top]=s[i];
else{
int pos=search(1,top,s[i]);
xu[pos+1]=s[i];
}
}
printf("%d\n",top);
return 0;
}