拦截导弹

题目描述

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

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

输入输出格式

输入格式:

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

输出格式:

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

输入输出样例

输入样例#1: 复制

389 207 155 300 299 170 158 65

输出样例#1: 复制

6
2


考虑一下200分\(n log n\)的做法

1437515-20180929200948218-971890447.png

  • 线段树
    不开O2和\(n^2\)得分是一样的(... 开了可过
#include<iostream>
#include<cstdio>
#define max(a,b) ((a)<(b)? (b) : (a))
#define update(now,a) a[now]=max(a[now*2],a[now*2+1])
using namespace std;

int i,m,n,j,k,a[400000],b[400001],f[400001],c[400001],g[400001],ans,ans2;

void gai(int now,int l,int r,int z,int w,int *a)
{
    if(l==r) {a[now]=z; return ; }
    int mid=(l+r)>>1;
    if(w<=mid) gai(now*2,l,mid,z,w,a);
    else gai(now*2+1,mid+1,r,z,w,a);
    update(now,a);
}

int search(int now,int l,int r,int z)
{
    if(r<=z) return b[now];
    int mid=(l+r)>>1,ans=0;
    ans=max(ans,search(now*2,l,mid,z));
    if(mid<z) ans=max(ans,search(now*2+1,mid+1,r,z));
    return ans;
}

int find(int now,int l,int r,int z)
{
    if(l>=z) return c[now];
    int mid=(l+r)>>1, ans=0;
    ans=max(ans, find(now*2+1,mid+1,r,z));
    if(mid>=z) ans=max(ans, find(now*2,l,mid,z));
    return ans;
}

int main()
{
    freopen("261.in","r",stdin);
    while(scanf("%d",&a[++n])!=EOF) m=max(m,a[n]);
    n-=1;
    for(int i=1;i<=n;i++)
    {
        f[i]=search(1,0,m,a[i]-1)+1;
        gai(1,0,m,f[i],a[i],b);
        ans=max(ans,f[i]);
        g[i]=find(1,0,m,a[i])+1;
        gai(1,0,m,g[i],a[i],c);
        ans2=max(ans2,g[i]);
    }
    printf("%d\n%d",ans2,ans);
}
  • 树状数组
    预计得分200
#include<iostream>
#include<cstdio>
#define max(a,b) ((a)<(b)? (b) : (a))
#define lowbit(x) ((x) &(-x))
using namespace std;

int i,m,n,j,k,a[400000],b[400001],c[400001],g[400001],ans,ans2;

int askl(int x)
{
    int ans=0;
    for(int i=x;i>0;i-=lowbit(i)) ans=max(ans,c[i]);
    return ans; 
}

int askr(int x)
{
    int ans=0;
    for(int i=x;i<=m;i+=lowbit(i)) ans=max(ans,b[i]);
    return ans;
}

void addl(int x,int z)
{
    for(int i=x;i>0;i-=lowbit(i)) b[i]=max(z,b[i]);
}

void addr(int x,int z)
{
    for(int i=x;i<=m;i+=lowbit(i)) c[i]=max(z,c[i]);
}

int main()
{
    while(scanf("%d",&a[++n])!=EOF) m=max(m,a[n]);
    n-=1;
    for(int i=1;i<=n;i++)
    {   
        k=askl(a[i])+1;
        addr(a[i]+1,k);
        ans=max(ans,k);
        k=askr(a[i])+1;
        addl(a[i],k);
        ans2=max(ans2,k);
    }
    printf("%d\n%d",ans2,ans);
    fclose(stdin);
}

转载于:https://www.cnblogs.com/ZUTTER/p/9726502.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值