题目链接:poj 1836
给定一队基佬的身高,在不改变原顺序的情况下,求最少让多少个人滚粗能使得整个队伍的身高满足从低到高再到低的分布。
正反向分别求一次最长公共子序列,求出第i个人正反向作为递增子序列的终点时的队伍的最长长度front[i],rear[i],求n-front[i]-rear[i+1]的最小值即为结果
//poj 1836
//双向最长递增子序列
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define FFF 1233
double a[FFF],c[FFF];//c存储已知的长度为i的则增序列的末尾最小值
int front[FFF],rear[FFF];
int qsearch(int x,double num)////找出比已有节点大的最小位置
{
int l=0,r=x,mid;
while(l<=r)
{
mid=(l+r)/2;
if(c[mid]<num)
l=mid+1;
else
r=mid-1;
}
return l;
}
int main()
{
int n,m;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lf",&a[i]);
}
memset(front,0,sizeof(front));
memset(rear,0,sizeof(front));
m=0;
for(int i=1;i<=n;i++)//找出正向时i作为末尾递增子序列的最长长度
{
int t=qsearch(m,a[i]);
if(t>m)
{
m=t;
c[t]=a[i];
}
else if(c[t]>a[i])
c[t]=a[i];
front[i]=t;
}
m=0;
for(int i=n;i>=1;i--)//找出反向时i作为末尾递增子序列的最长长度
{
int t=qsearch(m,a[i]);
if(t>m)
{
m=t;
c[t]=a[i];
}
else if(a[i]<c[t])
c[t]=a[i];
rear[i]=t;
}
int ans=1005;
/* for(int i=1;i<=n;i++)
cout<<front[i]<<' ';cout<<endl;
for(int i=1;i<=n;i++)
cout<<rear[i]<<' ';cout<<endl;
*/ for(int i=1;i<=n;i++)
{
for(int j=i+1;j<=n;j++)
{
int tmp=n-front[i]-rear[j];
if(tmp<ans)
ans=tmp;
}
}
cout<<ans<<endl;
return 0;
}