引用:
思路:
1、对于问一直接用O(n*logn)的方法求最长不升子序列即可。
求不升子序列的方法:
https://www.luogu.org/blogAdmin/article/edit/20362
2、对于问二求整个数列的最长上升子序列即可。证明如下:
(1)假设打导弹的方法是这样的:取任意一个导弹,从这个导弹开始将能打的导弹全部打完。而这些导弹全部记为为同一组,再在没打下来的导弹中任选一个重复上述步骤,直到打完所有导弹。
(2)假设我们得到了最小划分的K组导弹,从第a(1<=a<=K)组导弹中任取一个导弹,必定可以从a+1组中找到一个导弹的高度比这个导弹高(因为假如找不到,那么它就是比a+1组中任意一个导更高,在打第a组时应该会把a+1组所有导弹一起打下而不是另归为第a+1组),同样从a+1组到a+2组也是如此。那么就可以从前往后在每一组导弹中找一个更高的连起来,连成一条上升子序列,其长度即为K;
(3)设最长上升子序列长度为P,则有K<=P;又因为最长上升子序列中任意两个不在同一组内(否则不满足单调不升),则有
P>=K,所以K=P。
#include <cstdio>
#include <algorithm>
using namespace std;
int nn[100005],n=1,l1=1,l2=1,d[100005],f[100005];
bool cmp1(int a,int b){return a>=b;}
bool cmp2(int a,int b){return a>b;}
int max(int a,int b){return a>b?a:b;}
int main(){
while(scanf("%d",&nn[n])!=EOF)n++;n--;
//求最长不升子序列
d[1]=f[1]=nn[1];
for(int i=2;i<=n;i++){
if(d[l1]>=nn[i])d[++l1]=nn[i];
else d[upper_bound(d+1,d+l1+1,nn[i],cmp2)-d]=nn[i];
if(f[l2]<nn[i])f[++l2]=nn[i];
else f[lower_bound(f+1,f+l2+1,nn[i])-f]=nn[i];
}
printf("%d\n%d",l1,l2);
return 0;
}