Def:
LIS:最长上升子序列 指一个序列中最长的单调递增的子序列
LIS经常用于确定一个代价最小的调整方案,使一个序列变为升序。只需要固定LIS中的元素,调整其他元素即可。
上升子序列指的是对于任意的i<j都满足ai<aj的子序列,该问题被称为最长上升子序列
有两种时间复杂度:O(n*log n) and O(n*n) 但是空间复杂度均为 O(n)
若使用朴素的顺序查找在D1..Dlen查找,由于共有O(n)个元素需要计算,每次计算时的复杂度是O(n),则整个算法的时间复杂度为O(n^2),
若使用二分查找,整个算法时间复杂度将下降为O(n*logn),
为了更好地了解该算术复杂度 可以去尝试一下洛谷的 P2782 友好城市 由于算法复杂度过高 会导致 TLE 使用 std::lower_bound()才能AC
//https://blog.csdn.net/qq_40160605/article/details/80150252 侵删 关于lower_bound()的讲解
大佬blog https://baike.baidu.com/item/LIS/16018280 //百度百科实现算法 我没有仔细看 https://blog.csdn.net/George__Yu/article/details/75896330 //侵删 https://blog.csdn.net/ltrbless/article/details/81318935 //侵删
一.
友好城市 AC代码 相当于 一个 算法复杂度为O(n*log n)的模板


1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 const int range=1000010; 5 6 int N,ans,maxn,dp[range]; 7 8 struct node{ 9 int s; 10 int n; 11 }t[range]; 12 13 int cmp(node n1,node n2){ 14 return n1.s<n2.s; 15 } 16 17 void f(){ 18 for(int i=1;i<=N;i++){ 19 int maxn=lower_bound(dp+1,dp+ans+1,t[i].n)-dp; 20 dp[maxn]=t[i].n; 21 if(maxn>ans){ 22 ans++; 23 } 24 } 25 cout<<ans; 26 } 27 28 int main(){ 29 cin>>N; 30 for(int i=0;i<N;i++){ 31 cin>>t[i].s>>t[i].n; 32 } 33 sort(t,t+N,cmp); 34 dp[++ans]=t[0].n; 35 f(); 36 return 0; 37 }
//今天看的时候 发现了一个大佬blog https://blog.csdn.net/lxt_Lucia/article/details/81206439 有一个树状数组维护
二.
洛谷 P1091 合唱队形
题目:https://www.luogu.org/problem/P1091
AC代码


1 #include<iostream> 2 3 using namespace std; 4 5 int n,ans,t[1010],cre[1010],decre[1010]; 6 7 int main(){ 8 cin>>n; 9 for(int i=0;i<n;i++){ 10 cin>>t[i]; 11 cre[i]=0; 12 decre[i]=0; 13 } 14 for(int i=1;i<n;i++){ 15 for(int j=0;j<i;j++){ 16 if(t[i]>t[j]){ 17 cre[i]=max(cre[i],cre[j]+1); 18 } 19 } 20 } 21 for(int i=n-2;i>=0;i--){ 22 for(int j=n-1;j>i;j--){ 23 if(t[i]>t[j]){ 24 decre[i]=max(decre[i],decre[j]+1); 25 } 26 } 27 } 28 for(int i=0;i<n;i++){ 29 ans=max(ans,(cre[i]+decre[i]+1)); //把每个数的左边从低到高的数和右边从高到低的数相加 注意!!自己加了两次要-1 30 } 31 cout<<n-ans; 32 return 0; 33 }
类似题目: POJ2533 Longest Ordered Subsequence
AC代码


1 #include<iostream> 2 #include<algorithm> 3 using namespace std; 4 5 int n,a[1010],dp[1010]; 6 7 void f(){ 8 for(int i=0;i<n;i++){ 9 dp[i]=1; 10 for(int j=0;j<=i;j++){ 11 if(a[i]>a[j]) 12 dp[i]=max(dp[i],dp[j]+1); 13 } 14 } 15 sort(dp,dp+n); 16 cout<<dp[n-1]<<endl; 17 } 18 19 20 int main(){ 21 while(cin>>n&&n){ 22 for(int i=0;i<n;i++) 23 cin>>a[i]; 24 f(); 25 } 26 return 0; 27 }
三.
POJ 1458 Common Subsequence
题目


A subsequence of a given sequence is the given sequence with some elements (possible none) left out. Given a sequence X = < x1, x2, ..., xm > another sequence Z = < z1, z2, ..., zk > is a subsequence of X if there exists a strictly increasing sequence < i1, i2, ..., ik > of indices of X such that for all j = 1,2,...,k, x ij = zj. For example, Z = < a, b, f, c > is a subsequence of X = < a, b, c, f, b, c > with index sequence < 1, 2, 4, 6 >. Given two sequences X and Y the problem is to find the length of the maximum-length common subsequence of X and Y. Input The program input is from the std input. Each data set in the input contains two strings representing the given sequences. The sequences are separated by any number of white spaces. The input data are correct. Output For each set of data the program prints on the standard output the length of the maximum-length common subsequence from the beginning of a separate line. Sample Input abcfbc abfcab programming contest abcd mnp Sample Output 4 2 0
题解://解释一下输出应该就懂了 4--即abfb 2--on 0--0
AC代码


1 #include<iostream> 2 3 using namespace std; 4 string s1=" ",s2=" ",s3,s4; 5 int dp[10010][10010]; 6 7 void f(){ 8 for(int i=1;i<=s1.size();i++){ 9 for(int j=1;j<=s2.size();j++){ 10 if(s1[i]==s2[j]){ 11 dp[i][j]=dp[i-1][j-1]+1; 12 } 13 else{ 14 dp[i][j]=max(dp[i-1][j],dp[i][j-1]); 15 } 16 } 17 } 18 cout<<dp[s1.size()][s2.size()]-1<<endl; 19 s3.clear(); 20 s4.clear(); 21 s1.clear(); 22 s2.clear(); 23 s1=s2=" "; 24 } 25 26 int main(){ 27 while(cin>>s3>>s4){ 28 s1+=s3; 29 s2+=s4; 30 for(int i=0;i<=s1.size();i++){ 31 for(int j=0;j<=s2.size();j++){ 32 dp[i][j]=0; 33 } 34 } 35 f(); 36 } 37 return 0; 38 }
//坑爹的地方 即注意点
①string容器默认从“0”开始 但是在dp[]从0开始的情况下 会产生越界情况 雾解:给dp[0][0]赋值 然后dp[0][1]和dp[1][0]就死了 正解:用一个新的" "字符串与输入的字符数组相加 这样数组下标相当于是从1开始 (但是这里还有需要注意的地方,下面会提到)
②提交了n次之后 还是一直报 WA Dev诚不欺我 输出的答案和编译调试的结果不一样 被坑惨了 导致我一直以为是dp[]数组的问题 其实是string容器的问题 每次新输入的都没有清空 导致上一次的也参与运算 因此 clear函数必不可少 (菜鸡这个错误调了1个小时)
③由于在①中加了一个“ ”,因此结果多了1 这个时候应该 -1
emmmm 本题其实应该是用char[]数组会更方便一点