这题题目大意很清楚,之所以一开始没做是因为理解出错。
因为导弹不能上升,所以:
第一个要求是求出某枚导弹的最多拦截个数,这个很好理解,就是求解不上升的最长子序列
第二个要求是求出最少的拦截导弹个数,因为一枚导弹发射出去后就不能上升,所以要求出需要多少枚导弹,就是求出最长上升子序列,相当于敌机是一架一架的来, 一枚导弹一经发射就不可能后退或者上升,所以为对付后来的上升的飞机,就必须重新发射一枚导弹(一开始理解错了,以为要找出最少的能覆盖整个序列的几个上升的子序列)
还有就是这种算法是 N * logN的算法,好好理解下,至于O(n^2)的算法就不说了。。。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define inf 999999
#define maxn 100006
int num[maxn];
int dp[maxn]; //dp[i]表示以num[i]尾的最长子序列
int len;
int find_up(int L,int R,int x) //上升子序列的函数
{
if(L==R) return L;
int mid = (L+R)>>1;
if(dp[mid]<x) return find_up(mid+1,len,x);
else return find_up(L,mid,x);
}
int find_down(int L,int R,int x) //下降子序列的函数
{
if(L==R) return L;
int mid = (L+R)>>1;
if(dp[mid]>=x) return find_down(mid+1,len,x);
else return find_down(L,mid,x);
}
int main()
{
int n,j;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&num[i]);
//--------------------------------------
//以下是求解最长不上升子序列
len = 0;
dp[0] = inf;
for(int i=0;i<n;i++)
{
if(num[i] <= dp[len]) j = ++len;
else j = find_down(1,len,num[i]);
dp[j] = num[i];
}
printf("%d ",len);
//---------------------------------------
//以下是求解最长上升子序列
len = 0;
dp[0] = -inf;
for(int i=0;i<n;i++)
{
if(num[i] > dp[len]) j = ++len;
else j = find_up(1,len,num[i]);
dp[j] = num[i];
}
printf("%d\n",len);
}
return 0;
}