LIS和LCS
LIS 模板
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int arr[100000+10],n;
vector<int> vs;
/*
lis问题模板,使用二分+贪心
if(arr[i]>arr[i-1])
vector.push(arr[i])
else
vector中大于arr[i]的最小的数变成arr[i]
*/
int main(){
freopen("data.in","r",stdin);
cin>>n;
for(int i=1;i<=n;i++)
cin>>arr[i];
vs.push_back(arr[1]);
int ind;
for(int i=2;i<=n;i++){
if(arr[i]>vs.back()){
vs.push_back(arr[i]);
}else{
ind = lower_bound(vs.begin(),vs.end(),arr[i])-vs.begin();
vs[ind] = arr[i];
}
}
// vs的长度就是最长上升子序列的长度
for(int i=0;i<vs.size();i++)
cout<<vs[i]<<" ";
return 0;
}
1020 导弹拦截
-
思路:
- 本题要求两个东西,第一个很明显就是最长不下降子序列,第二问在不知道的情况下很难想到是最长上升子序列...
- 这次借鉴(照抄)的是w1049344862的写法,巧妙的使用lower_bound和upper_bound使得最长上升子序列和最长下降子序列变得异常简单
-
重点
-
lower_bound会查找第一个大于等于要找的数,而upper_bound是大于要找的数的数
int arr[10] = {1,2,3,4,5,6,7,8,9,10}; int ind1 = lower_bound(arr,arr+10,3)-arr; cout<<ind1<<endl; int ind2 = upper_bound(arr,arr+10,3)-arr; cout<<ind2; // 输出 2 3
-
最奇技淫巧的地方:使用greater()来让upper_bound变成求第一个小于要找的数
-
也就是说,LIS的模板只需要少量代码修改就能变成求LCS
if(arr[i]<=vs.back()){ vs.push_back(arr[i]); }else{ ind = upper_bound(vs.begin(),vs.end(),arr[i])-vs.begin(); vs[ind] = arr[i]; }
只能说大佬666
-
ac代码
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int arr[100000+10],n;
vector<int> vs1,vs2;
int main(){
freopen("data.in","r",stdin);
while(cin>>arr[n]){
n++;
}
vs1.push_back(arr[0]);
vs2.push_back(arr[0]);
int ind;
for(int i=1;i<n;i++){
// 最长上升子序列
if(arr[i]>vs1.back()){
vs1.push_back(arr[i]);
}else{
ind = lower_bound(vs1.begin(),vs1.end(),arr[i])-vs1.begin();
vs1[ind] = arr[i];
}
if(arr[i]<=vs2.back()){
vs2.push_back(arr[i]);
}else{
ind = upper_bound(vs2.begin(),vs2.end(),arr[i],greater<int>())-vs2.begin();
vs2[ind] = arr[i];
}
}
cout<<vs2.size()<<endl<<vs1.size();
return 0;
}