codevs 2188 最长上升子序列
题目描述 Description
LIS问题是最经典的动态规划基础问题之一。如果要求一个满足一定条件的最长上升子序列,你还能解决吗?
给出一个长度为N整数序列,请求出它的包含第K个元素的最长上升子序列。
例如:对于长度为6的序列<2,7,3,4,8,5>,它的最长上升子序列为<2,3,4,5>,但如果限制一定要包含第2个元素,那么满足此要求的最长上升子序列就只能是<2,7,8>了。
输入描述 Input Description
第一行为两个整数N,K,如上所述。
接下来是N个整数,描述一个序列。
输出描述 Output Description
请输出两个整数,即包含第K个元素的最长上升子序列长度。
样例输入 Sample Input
8 6
65 158 170 299 300 155 207 389
样例输出 Sample Output
4
数据范围及提示 Data Size & Hint
80%的数据,满足0<n<=1000,0<k<=n
100%的数据,满足0<n<=200000,0<k<=n
题解:清北第二套题的第二道题考试的时候写炸了,这引起我的反思,要复习一下最长上升子序列。然后就找了个最长上升子序列的题。这道题增加的一点难度是必须含有第k个元素。稍微进行一下修改即可。
当查找的第k个元素时,由于必须包含k,所以k插入位置x即为此时找到的最长上升子序列的长度。因为f数组中f[x]以后的数都是在k之前出现的比k大的数。此是f[1]~f[x]为一固定的序列,不再发生变化。然后a数组往后查找时,若有比a[k]小的数,直接忽略不进行运算。就避免了f[1]~f[k]序列中的数发生变化。
#include<cstdio> #include<iostream> #define N 200100 using namespace std; int n,k,len=1,l=0; int a[N]; int f[N]; int erfen(int l,int r,int p) { if (l>r) return l; int mid=(l+r)>>1; if (f[mid]<p) erfen(mid+1,r,p); else erfen(l,mid-1,p); } int main() { scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) scanf("%d",&a[i]); f[len]=a[1]; for (int i=2;i<=n;i++) { if (i>k&&a[i]<a[k]) continue;//忽略比a[k]小的数 int bj; if (a[i]>f[len]) f[++len]=a[i],bj=len; else bj=erfen(l,len,a[i]); if (bj>len) len=bj; f[bj]=a[i]; if (i==k) l=len=bj;//长度进行更改 } printf("%d",len); return 0; }
I'm so lost but not afraid ,I've been broken and raise again