最长上升子序列和Dilworth定理 以及二分优化
#include<iostream>
using namespace std;
int dp[100005],a[100005],n,maxx=-999;
//dp[i]记录以i结尾的最长上升子序列
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>a[i],dp[i]=1;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1);
}
maxx=max(maxx,dp[i]);
}
cout<<maxx;
return 0;
}
//O(n^2)代码
Dilworth定理:通俗解释: 把一个数列划分成最少的最长不升子序列的数目就等于这个数列的最长上升子序列的长度(LIS)
利用二分查找优化
例题洛谷P1020
题目很简单,分别求出最长不上升子序列和最长上升子序列就是答案(根据Dilworth定理)
100分代码 (动态规划O(n^2))
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int dp1[maxn],dp2[maxn];
int cnt=1,max1,max2;
int main(){
//freopen("testdata.in", "r", stdin);
while(cin>>a[cnt]){
dp1[cnt]=1;
dp2[cnt]=1;
cnt++;
}
cnt--;
// for(int i=1;i<=cnt;i++){
// cout<<a[i]<<" ";
// }
for(int i=1;i<=cnt;i++){
for(int j=1;j<i;j++){
if(a[j]>=a[i]){
dp1[i]=max(dp1[i],dp1[j]+1);
}
else if(a[j]<a[i]){
dp2[i]=max(dp2[i],dp2[j]+1);
}
max1=max(max1,dp1[i]);
max2=max(max2,dp2[i]);
}
}
cout<<max1<<endl;
cout<<max2;
return 0;
}
200分代码 (二分优化 O(n*logn))
#include <iostream>
#include<algorithm>
#include<cstdio>
#include<vector>
#include<queue>
#include<stack>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
int a[maxn];
int dp1[maxn],dp2[maxn];
bool cmp(const int &a,const int &b){
return a>b;
}
int cnt=1,len1=1,len2=1;
void fun1(int i){
if(a[i]>dp1[len1]){
dp1[++len1]=a[i];
}
else if(a[i]<=dp1[len1]){
int temp=lower_bound(dp1+1,dp1+len1+1,a[i])-dp1;
dp1[temp]=a[i];
}
}
void fun2(int i){
if(a[i]<=dp2[len2]){
dp2[++len2]=a[i];
}
else if(a[i]>dp2[len2]){
int temp=upper_bound(dp2+1,dp2+len2+1,a[i],cmp)-dp2;
dp2[temp]=a[i];
}
}
int main(){
//freopen("testdata.in", "r", stdin);
while(cin>>a[cnt]){
dp1[cnt]=1;
dp2[cnt]=1;
cnt++;
}
cnt--;
dp1[1]=a[1],dp2[1]=a[1];
for(int i=2;i<=cnt;i++){
fun1(i);
fun2(i);
}
cout<<len2<<endl;
cout<<len1;
return 0;
}
原理如下


浙公网安备 33010602011771号