P1020导弹拦截

题目描述

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

输入导弹依次飞来的高度(雷达给出的高度数据是\le 50000≤50000的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

输入输出格式

输入格式:

 

11行,若干个整数(个数\le 100000≤100000)

 

输出格式:

 

22行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。

 

输入输出样例

输入样例#1: 复制

389 207 155 300 299 170 158 65

输出样例#1: 复制

6
2

 

 

这道题用来入门lis和lds非常好,用了俩天时间才搞懂,头疼死,我队友一个小时就都弄懂了,没法比,没法比,有天赋的人真的牛掰神仙,像我这种弱鸡只能不停的思考总结,哎!!不多说上题解。

这道题是用来求一个最长非升子序列和最长上升子序列。第一问很明显就是最长非升子序列,那么最长上升怎么看出来的呢?

因为我每次划分最长的一条导弹序列为a,剩下的a + 1总能找到比它更高,a + 2比a + 1高,所以,转换一下就是求最长上升子序列。

这道题手写一个二分查找不知道为什么不能都过,后来用lower_bound和upper_bound,哇学这俩个函数的第四个参数用法花了我俩天时间,各种试终于搞懂了!!

首先说下lower_bound

struct cmp //upper a代表要比较的数字,b代表num数组,如果return为1就往左跑,否则往右跑
{
    bool operator()(int a, int b)
    {
        return a > b;
    }
};

 

 a代表数组,b代表比较数字,如果return为1就往右跑,否则往左跑

upper比较奇葩是相反的。然后我死活过不去落谷的那道题

最长非降子序列用Upper最长上升用lower

说一下基本思路:

对于最长非降

就是维护一个堆,如果比我当前的数组最大的元素等于或者大于,那么往后添加。

如果比我的小,那么我就从我当前的数组里面找到第一个大于我的数,然后更新它,因为(1~i -1)总比我小,我替换i位置

使得我的潜力更加的大,因为我比它小。所以用stl upper_bound就不错,手写一个二分有毒过不去有大佬指教下。

对于最长上升,如果比我最大的大,往后添加,如果=不用管,如果<的话就需要找到第一个大于等于它的替换掉就好了。

然后用stl的lower_bound

上代码:

# include 
# include 
# include 
# include 
using namespace std;
//找到第一个大于它的d的下标,如果是最长上升子序列,这里变成lower_bound
//最长不下降序列用upper_bound
const int maxn = 100005;

int arr[maxn], dp[maxn], up_d[maxn];
int Binary_Search(int arr[], int r, int x)
{
    int l = 1, mid;
    while(l <= r)
    {
        mid = (r + l) >> 1;
        if(arr[mid]<=x)
        {
            l = mid + 1;
        }
        else
            r = mid - 1;

    }
    return l;
}
struct cmp //upper a代表要比较的数字,b代表num数组,如果return为1就往左跑,否则往右跑
{
    bool operator()(int a, int b)
    {
        return a > b;
    }
};

int main(int argc, char *argv[])
{
    memset(arr, false, sizeof(arr));
    memset(dp, false, sizeof(dp));
    memset(up_d, false, sizeof(up_d));
    int n = 1;
    while(scanf("%d",&arr[n])!=EOF)
    {
        n++;
    }
    n--;
    dp[1] = arr[1];
    int ans = 1, up = 1;
    up_d[1] = arr[1];
    for(int i = 2; i <= n ; i++)
    {
        if(arr[i] <= dp[ans])
        {
            dp[++ans] = arr[i];
        }
        else
        {
            int pos = upper_bound(dp + 1, dp + ans + 1, arr[i], cmp()) - dp;
            dp[pos] = arr[i];
        }
        # if 01
        if(up_d[up] < arr[i])
        {
            up_d[++ up] = arr[i];
        }
        else
        {
            int pos = lower_bound(up_d + 1, up_d + up + 1, arr[i]) - up_d;
            up_d[pos] = arr[i];
        }
        #endif
    }

    cout << ans << " " << up << endl;

    return 0;
}

 

 

你可能感兴趣的:(ACM算法题,动态规划)