例题
动态规划,f[i] 表示 以第 i 个数结尾的最长上升子序列的长度。
n平方级别:
#include <iostream> #include <algorithm> #include <cstring> using namespace std; //表示: f[i]表示以第i个数 为结尾的最长上升子序列; //属性: 最大值 //计算; f[i]=max(f[i],f[j]+1) j<=i; //初始化 const int N=1010; int n; int a[N]; int f[N]; int main() { cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; for(int i=1;i<=n;i++) { f[i]=1; for(int j=1;j<=i;j++) if(a[i]>a[j]) f[i]=max(f[i],f[j]+1); } int res=0; for(int i=1;i<=n;i++) res=max(res,f[i]); cout<<res; return 0; }
优化,有三份代码:第一二份是优化了算法,可以利用贪心+二分优化递推的过程。
第三份是记录路径。
//思路:单调栈; //如果 a[i]>stake.back() 直接插入; //否则,贪心的思想,二分找到第一个大于等于a[i] //的数进行替换,因为最后一个数最小一定更优; //但是不能存路径了 //较小的数开头的数作为的子序列 比 较大的数作为开头的子序列 更好 //如样例: //7 //1 2 8 9 10 5 6 //输出: //5 //1 2 5 6 10 #include <bits/stdc++.h> #define int long long //(有超时风险) #define PII pair<int,int> #define endl '\n' #define LL __int128 using namespace std; const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f; int a[N],b[N],c[N],pre[N]; signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; vector<int>q; q.push_back(a[1]); for(int i=1;i<=n;i++) { if(a[i]>q.back()) q.push_back(a[i]); else { //vector<int>::iterator auto k= lower_bound(q.begin(),q.end(),a[i]); *k=a[i]; } } cout<<q.size()<<endl; return 0; } #include <bits/stdc++.h> #define int long long //(有超时风险) #define PII pair<int,int> #define endl '\n' #define LL __int128 using namespace std; const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f; int cnt=0; int a[N],f[N]; int check(int x) { int l=1,r=cnt; while(l<r) { int mid=(l+r)/2; if(f[mid]>=x)r=mid; else l=mid+1; } return l; } signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; f[++cnt]=a[1]; for(int i=1;i<=n;i++) { if(a[i]>f[cnt])f[++cnt]=a[i]; else { int tmp=check(a[i]); f[tmp]=a[i]; } } cout<<cnt<<endl; return 0; } //还是可以记录路径的 #include <bits/stdc++.h> #define int long long //(有超时风险) #define PII pair<int,int> #define endl '\n' #define LL __int128 using namespace std; const int N=2e5+10,M=1e3+10,mod=998244353,INF=0x3f3f3f3f; int a[N],b[N],c[N],pre[N],f[N]; string ans[N]; signed main() { std::ios::sync_with_stdio(false); std::cin.tie(nullptr); int n;cin>>n; for(int i=1;i<=n;i++) cin>>a[i]; int len=0;//表示当前最长上升子序列长度 //ans[k]表示以k为长度的子序列的最优方案。 for(int i=1;i<=n;i++) { auto k= lower_bound(f+1,f+len+1,a[i])-f; f[k]=a[i]; len=max(len,k); cout<<f[k]<<endl; cout<<a[i]<<' '<<k<<' '<<ans[k]<<endl; ans[k]=ans[k-1]+to_string(a[i]); } cout<<ans[len]<<endl; return 0; }
最长上升子序列--模板
文章介绍了如何使用动态规划优化求解最长上升子序列问题,包括基本方法、贪心+二分优化以及记录路径的方法,重点讨论了单调栈和二分查找在算法中的应用。
摘要由CSDN通过智能技术生成