洛谷1020 NOIP1999 导弹拦截 dp

题目描述

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

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

我这里讲的是nlogn的做法。
首先看第一问,第一问就是要求一个最长不下降子序列,这个O(n^2)的做法是很容易的。
我这里介绍的nlogn的方法是用线段树的。我们发现高度是不超过50000的,所以我们可以把线段树的每一个下标i的含义变为目前加进来的高度为i的最长不下降子序列的长度是多少。然后我们需要做的是从后往前扫,每到一个位置,查询当前线段树从1到当前高度a[i]的区间最大值,当前的dp[i]即为那个最大值再加1,然后用dp[i]更新线段树即可。

然后看第二问,据说有个关于偏序集的定理,但是我觉得不太好理解,于是我自己想了一种理解方式。
我们考虑如果需要多出一套系统,就意味着现在出现的这一个导弹的高度比上一个导弹高,这样就不能用一套系统拦截这两个导弹了,我们此时就需要新加一个系统。所以我们把第二问转化为了求最长上升子序列的长度。

下面是代码:
#include <bits/stdc++.h>
using namespace std;

int n,a[200001],dp[200001],res;
struct node
{
    int l,r,mx;
}tr[205002];
void build(int rt,int l,int r)
{
    tr[rt].l=l;
    tr[rt].r=r;
    if(l==r)
    {
        tr[rt].mx=0;
        return;
    }
    int mid=(l+r)>>1;
    build(rt<<1,l,mid);
    build(rt<<1|1,mid+1,r);
    tr[rt].mx=0;
}
void add(int rt,int le,int ri,int x)
{
    int l=tr[rt].l,r=tr[rt].r;
    if(l>ri||r<le)
    return;
    if(le<=l&&r<=ri)
    {
        tr[rt].mx=max(tr[rt].mx,x);
        return;
    }
    int mid=(l+r)>>1;
    if(le<=mid) 
    add(rt<<1,le,ri,x);
    if(ri>mid)
    add(rt<<1|1,le,ri,x);
    tr[rt].mx=max(tr[rt<<1].mx,tr[rt<<1|1].mx);
}
int query(int rt,int le,int ri)
{
    int l=tr[rt].l,r=tr[rt].r,ans=0;
    if(l>ri||r<le)
    return 0;
    if(le<=l&&r<=ri)
    return tr[rt].mx;
    int mid=(l+r)>>1;
    if(le<=mid)
    ans=query(rt<<1,le,ri);
    if(ri>mid)
    ans=max(ans,query(rt<<1|1,le,ri));
    return ans;
}
int main()
{
    while(~scanf("%d",&a[++n]));
    build(1,1,50000);
    for(int i=n;i>=1;i--)
    {
        dp[i]=query(1,1,a[i])+1;
        add(1,a[i],a[i],dp[i]);
        res=max(res,dp[i]);
    }
    printf("%d\n",res);
    memset(dp,0,sizeof(dp));
    res=0;
    build(1,1,50000);
    for(int i=1;i<=n;i++)
    {
        dp[i]=query(1,1,a[i]-1)+1;
        add(1,a[i],a[i],dp[i]);
        res=max(res,dp[i]);
    }
    printf("%d\n",res);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/forever_shi/article/details/80224102