最长不下降子序列 最长不升子序列 最长上升子序列 最长下降子序列 n^2 nlogn
以洛谷P1020 导弹拦截为例
O(n^2)算法
AC代码如下
//1999 导弹拦截
#include <stdio.h>
#include <string.h>
int a[100+10];
int d[100+10];
int t[100+10];
int main(){
int v;
int n=0;
int i,j;
int maxd,maxt;
memset(a,0,sizeof(a));
memset(d,0,sizeof(d));
memset(t,0,sizeof(t));
while(scanf("%d",&v)==1){
a[n]=v;
n++;
}
//下降序列
d[0]=1;
for(i=1;i<n;i++){
d[i]=1;
for(j=0;j<i;j++){
if(a[j]>a[i]&&d[j]+1>d[i])
d[i]=d[j]+1;
}
}
//上升序列
t[0]=1;
for(i=1;i<n;i++){
t[i]=1;
for(j=0;j<i;j++){
if(a[j]<a[i]&&t[j]+1>t[i])
t[i]=t[j]+1;
}
}
maxd=1;
maxt=1;
for(i=0;i<n;i++){
if(maxd<d[i])
maxd=d[i];
if(maxt<t[i])
maxt=t[i];
}
printf("%d\n",maxd);
printf("%d\n",maxt);
return 0;
}
O(nlogn)算法
AC代码如下
#include <stdio.h>
int a[100100],d[100100];
int main(){
int i,k=1,ans1=0,left,right,mid,ans2=0;
while(scanf("%d",&a[k])!=EOF)k++;
d[0]=60000;
for(i=1;i<k;i++)//递减序列处理
if(d[ans1]>=a[i])
ans1++,d[ans1]=a[i];//d[]是递减序列
else{
left=0,right=ans1;
while(left+1<right){
mid=(left+right)/2;
if(d[mid]>=a[i])left=mid;//此处写成 if(d[ans1]>=a[i])left=mid;
else right=mid;
}
d[right]=a[i];//目标,让该递减序列,每个位置的值都尽可能大
}
printf("%d\n",ans1);
d[0]=-1;
for(i=1;i<k;i++)//严格递增序列处理
if(d[ans2]<a[i])
ans2++,d[ans2]=a[i];
else{
left=0,right=ans2;
while(left+1<right){
mid=(left+right)/2;
if(d[mid]<a[i])left=mid;
else right=mid;
}
d[right]=a[i];//想清数据存储格式,采用left还是right,自然明白
}
printf("%d\n",ans2);
return 0;
}