[dp]最长单调递增子序列LIS
https://www.51nod.com/tutorial/course.html#!courseId=12
解题关键:
如果将子序列按照长度由短到长排列,将他们的最大元素放在一起,形成新序列$B\left\{ {{b_1},{b_2}, \ldots \ldots ,{b_j}} \right\}$,则序列$B$满足${b_1} < {b_2} < \ldots \ldots < {b_j}$。这个关系比较容易说明,假设${b_{xy}}$表示序列A中长度为$x$的递增序列中的第$y$个元素,显然,如果在序列$B$中存在元素${b_{mm}} > {b_{nn}}$,且$m < n$则说明子序列${B_n}$的最大元素小于${B_m}$的最大元素,因为序列是严格递增的,所以在递增序列${B_n}$中存在元素${b_{nm}} < {b_{nn}}$,且从${b_{n0}}$到${b_{nm}}$形成了一个新的长度为$m$的递增序列,因为${b_{mm}} > {b_{nn}}$,所以${b_{mm}} > {b_{nm}}$,这就说明在序列$B$中还存在一个长度为$m$,最大元素为${b_{nm}} < {b_{mm}}$的递增子序列,这与序列的定义,${b_{mm}}$是所有长度为m的递增序列中第$m$个元素最小的序列不符,所以序列$B$中的各元素严格递增。
注意liss存的是下标,主要是为了求pre用,若只求max,你当然可以设成值。
爆炸了,刚发现《挑战竞赛程序设计》上有一个代码非常非常简短的模板,炸了;
STL模板:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<functional> using namespace std; const int N=131072; int n=7, a = {0,0,1,1,0,0,2}; template<class Cmp> int LIS (Cmp cmp){ static int m=0,end ; for(int i=0;i<n;i++){ int pos=lower_bound(end,end+m,a[i],cmp)-end; end[pos]=a[i],m+=pos==m; } return m; } bool greater1(int value){ return value>=1; } int main(){ cout<<LIS(less<int>())<<endl; //严格上升 cout<<LIS(less_equal<int>())<<endl; //非严格上升 cout<<LIS(greater<int>())<<endl; //严格下降 cout<<LIS(greater_equal<int>())<<endl;//非严格下降 cout<<count_if(a,a+7,greater1)<<endl; //计数 //第二个参数为末尾元素的下一个位置 return 0; }
最终模板:
#include<bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; ll a[50002],dp[50002]; int main(){ int n; cin>>n; for(int i=0;i<n;i++){ cin>>a[i]; } fill(dp,dp+n,INF); for(ll i=0;i<n;i++){ *lower_bound(dp,dp+n,a[i])=a[i]; } printf("%lld\n",lower_bound(dp,dp+n,INF)-dp); }
自己改进模板(不带路径):注意二分时上界为len+1就ok了,也可以fill成inf,更简单明了
#include<bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; int arr[50002],dp[50002]; int n,len; int find1(int x){ int mid,l=1,r=len+1; while(l<r){ mid=(l+r)>>1; if(dp[mid]>x) r=mid; else l=mid+1; } return r; } int lis(){ int dex; for(int i=1;i<=n;i++){ dex=find1(arr[i]); dp[dex]=arr[i]; len=max(len,dex); } return len; } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>arr[i]; } ll ans=lis(); printf("%lld\n",ans); return 0; }
带路径模板1
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> using namespace std; typedef long long ll; int a[50002],dp[50002],pre[50002],res[50002],n; int len; int find1(int x){ int mid,l=1,r=len+1; while(l<r){ mid=(l+r)>>1; if(a[dp[mid]]>x) r=mid; else l=mid+1; } return r; } int lis(){ len=0; for(int i=1;i<=n;i++){ int dex=find1(a[i]); dp[dex]=i; if(dex!=1) pre[i]=dp[dex-1]; len=max(len,dex); } int k=dp[len],t=len; while(pre[k]!=k){ res[t--]=a[k]; k=pre[k]; } res[t]=a[k]; return len; } int main(){ cin>>n; for(int i=0;i<=n+2;i++) pre[i]=i; for(int i=1;i<=n;i++) cin>>a[i]; ll ans=lis(); printf("%lld\n",ans); for(int i=1;i<=ans;i++){ printf("%d ",res[i]); } printf("\n"); }
带路径模板2
#include<cstdio> #include<cstring> #include<algorithm> #include<cstdlib> #include<iostream> using namespace std; typedef long long ll; int arr[50002],liss[50002],pre[50002],res[50002]; int find1(int i,int l,int r){ int mid; while(l<r){ mid=(l+r)>>1; if(arr[liss[mid]]>arr[i]) r=mid; else l=mid+1; } return r; } int lis(int len){ int max=1; liss[0]=0; for(int i=0;i<len;i++){ int index=find1(i,0, max-1); if(index==0&&arr[liss[index]]>=arr[i]){ liss[index]=i; continue; }//增加这条语句主要是pre的影响,不需要路径的话,完全可以去掉。 if(index==max-1&&arr[liss[index]]<arr[i]){ liss[max++]=i; pre[i]=liss[index]; continue; } liss[index]=i; pre[i]=liss[index-1]; } int k=liss[max-1],t=max-1; while(pre[k]!=k){ res[t--]=arr[k]; k=pre[k]; } res[t]=arr[k]; return max; } int main(){ int n; cin>>n; for(int i=0;i<n+2;i++){ pre[i]=i; } for(int i=0;i<n;i++){ cin>>arr[i]; } ll ans=lis(n); printf("%lld\n",ans); for(int i=0;i<ans;i++){ printf("%d ",res[i]); } printf("\n"); }
- HDUOJ 1025 - ConstructingRoadsInJGShining'sKingdom(DP:最长递增子序列LIS【nlogn算法】)
- 最长单调递增子序列LIS
- 单调递增子序列LIS (DP)
- DP之最长递增子序列LIS
- (DP6.1.4.1)UVA 111 History Grading(最长递增子序列LIS 的LCS 解法)
- LIS(最长递增子序列) Zigzag
- HDU - 1257 最少拦截系统(LIS最长递增子序列)
- POJ1631最长单调递增子序列
- 最长单调递增子序列
- poj 2533 (LIS 最长递增子序列)
- 最长单调递增子序列
- LIS(最长上升子序列两种算法模板)DP模板,并且输出序列
- 最长递增子序列LIS
- 【POJ2533】Longest Ordered Subsequence(LIS-最长上升子序列/DP)
- POJ 2533 - Longest Ordered Subsequence(dp 最长递增子序列)
- NOJ 16题 矩形嵌套 DP(单调递增子序列)
- dp之最长递增子序列模板poj3903
- LIS(最长递增子序列) Zigzag
- 【串和序列处理 7】LIS 最长递增子序列
- LIS-最长递增子序列