T1朴素的最长严格上升子序列
http://codevs.cn/problem/3955/
给一个数组a1, a2 ... an,找到最长的上升降子序列ab1<ab2< .. <abk,其中b1<b2<..bk。
输出长度即可。
输入描述 Input Description
第一行,一个整数N。
第二行 ,N个整数(N < = 1000000)
输出描述 Output Description
输出K的极大值,即最长严格上升子序列的长度
样例输入 Sample Input
5
9 3 6 2 7
样例输出 Sample Output
3
n²做法:f[i]=j表示以第i个数结尾的最长上升子序列长度为j
#include<cstdio> #include<algorithm> using namespace std; int n,a[5001],f[5001],ans; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<=n;i++) { int maxn=0; for(int j=1;j<i;j++) if(a[i]>a[j]&&maxn<f[j]) maxn=f[j]; f[i]=maxn+1; ans=max(f[i],ans); } printf("%d",ans); }
nlogn做法:f[i]=表示长度为i的最长上升子序列中,第i个数最小是j,二分查找
#include<cstdio> using namespace std; int n,f[5001],s,x; int main() { scanf("%d",&n); for(int i=1;i<=n;i++) { scanf("%d",&x); if(x>f[s]) { f[++s]=x; continue; } int l=0,r=s,k; while(l<=r) { int m=l+r>>1; if(x>f[m]) { l=m+1; k=m; } else r=m-1; } if(f[k+1]>x) f[k+1]=x; } printf("%d",s); }
T2 包含第k个数的最长上升子序列
http://codevs.cn/problem/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个数的都删去,然后套上面的方法
#include<cstdio> using namespace std; int n,a[200001],f[200001],s,k,x; int main() { scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]); for(int i=1;i<k;i++) if(a[i]>=a[k]) a[i]=-1; for(int i=1;i<=n;i++) { if(a[i]==-1) continue; if(i>k&&a[i]<=a[k]) continue; if(a[i]>f[s]) { f[++s]=a[i]; continue; } int l=0,r=s,p=0; while(l<=r) { int m=l+r>>1; if(a[i]>f[m]) { l=m+1; p=m; } else r=m-1; } if(f[p+1]>a[i]) f[p+1]=a[i]; } printf("%d",s); }