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)的模板
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }