给你一串序列 让你找到最长不上升子序列的长度 和 最少有几个不上升子序列
样例就是389 300 299 170 158 65是最长不上升子序列
那么最多有两个不上升子序列 另一组就是207 155
求最长不上升子序列的组数就是求最长上升子序列的长度 因为后面一旦有一个高度突然上升超过前面的就构不成下降
不上升可以有相等的数 倒着求最长上升时小于等于
Sample Input
8
389 207 155 300 299 170 158 65
389 389 155 300 299 170 158 65
8
7 6 5 6 3 2 4 1
Sample Output
2
2
LIS板子写法
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+5;
const ll mod=1e9+7;
const int INF=0x3f3f3f3f;
ll T,n,m,h,ans1,ans2;
ll a[maxn],b[maxn],dp[maxn],dp2[maxn],f,res;
string s;
vector<ll> v;
int main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
dp[i]=1;dp2[i]=1;
}
// for(int i=1;i<=n;i++){
// dp[i]=INF;dp2[i]=INF;
// }
for(int i=1;i<=n;i++)
b[i]=a[n-i+1];
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(a[j]<a[i])
dp[i]=max(dp[i],dp[j]+1);
}
}
for(int i=1;i<=n;i++){
ans1=max(ans1,dp[i]);
}
cout<<ans1<<endl;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
if(b[j]<=b[i]){
dp2[i]=max(dp2[i],dp2[j]+1);
}
}
}
for(int i=1;i<=n;i++){
ans2=max(ans2,dp2[i]);
}
cout<<ans2<<endl;
/*
for(int i=1;i<=n;i++){
*lower_bound(dp+1,dp+n+1,a[i])=a[i]; //严格递增LIS 所以可以替换大于等于
}
cout<<lower_bound(dp+1,dp+n+1,INF)-dp-1<<endl;
for(int i=1;i<=n;i++){
*upper_bound(dp2+1,dp2+n+1,b[i])=b[i];
}
cout<<lower_bound(dp2+1,dp2+n+1,INF)-dp2-1<<endl;*/
return 0;
}
单调栈
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
#define IO ios::sync_with_stdio(false);cin.tie(0);
ll n,m,dp[maxn],dp2[maxn],a[maxn],b[maxn],st[maxn],s[maxn],top,maxx;
int main(){
while(cin>>n){
top=0;maxx=0;
for(int i=0;i<n;i++){
dp[i]=1;dp2[i]=1;a[i]=0;b[i]=0;
}
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
b[i]=a[n-i-1];
st[top]=a[0];
for(int i=1;i<n;i++){
if(st[top]<a[i]){
st[++top]=a[i];
dp[i]=top+1;
}
else{
ll l=0,r=top;
while(l<=r){
ll mid=(l+r)/2;
if(st[mid]<a[i])
l=mid+1;
else
r=mid-1;
}
st[l]=a[i];//l==r
dp[i]=l+1;
}
}
for(int i=0;i<n;i++){
maxx=max(maxx,dp[i]);
}
cout<<maxx<<endl;
top=0;maxx=0;
s[top]=b[0];//倒着不严格单调递增
for(int i=1;i<n;i++){
if(s[top]<=b[i]){
s[++top]=b[i];
dp2[i]=top+1;
}
else{
ll l=0,r=top;
while(l<=r){
ll mid=(l+r)/2;
if(s[mid]<=b[i])
l=mid+1;
else
r=mid-1;
}
s[l]=b[i];
dp2[i]=l+1;
}
}
for(int i=0;i<n;i++){
maxx=max(maxx,dp2[i]);
}
cout<<maxx<<endl;
}
return 0;
}
/*
8 389 389 155 300 299 170 158 65
*/
AP
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define forn(i, n) for(int i = 0; i < n; ++i)
#define for1(i, n) for(int i = 1; i <= n; ++i)
#define IO ios::sync_with_stdio(false);cin.tie(0)
const int maxn = 1e5 + 5;
const int inf = 2e9;
int lis[maxn], a[maxn], pos[maxn];
inline void init() {
forn(i, maxn) lis[i] = inf;
}
int main() {
IO;
init();
int n; cin >> n;
int len = 0;
forn(i, n) {
cin >> a[i];
int p = lower_bound(lis, lis + n, a[i]) - lis;//求组数 严格单调 所以相等位置可以替换
if(p == len) ++len;
lis[p] = a[i], pos[i] = len;
}
cout << len << '\n';
int now = len;
for(int i = n - 1; now >= 1 && i >= 0; --i) {//用lis可以记录
if(pos[i] == now) lis[now--] = a[i];
}
for1(i, len) cout << lis[i] << ' ';
return 0;
}
HDU1257 n=30000 nlogn
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const int maxn=1e5+5;
ll a[maxn],b[maxn],dp[maxn],n,top,st[maxn];
int main()
{
while(cin>>n){
top=0;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
memset(dp,0,sizeof(dp));
memset(st,0,sizeof(st));
for(ll i=0;i<n;i++){
cin>>a[i];
}
for(ll i=0;i<n;i++){
dp[i]=1;
}
int i,j;
top = 0;
st[top] = a[0];
for(i=1; i<n; ++i)//正着求最长上升子序列的长度
{
if(a[i] > st[top])//维护一个满足递增条件 都压进栈
{
st[++top] = a[i];
dp[i] = top +1 ;
}
else
{
int low = 0, high = top;
while(low <= high)
{
int mid = (low + high) >> 1;
if(st[mid]<a[i])
low = mid + 1;
else
high = mid - 1;
}
st[low] = a[i];
dp[i] = low +1;
}
}
ll ans=0;
for(ll i=0;i<n;i++){
ans=max(ans,dp[i]);
}
cout<<ans<<endl;
}
}