一箭多雕

一箭多雕
时间限制: 1 sec 内存限制: 128 MB

题目描述

小明喜欢武侠小说,在武侠世界里,他不但练就了一箭双雕的能力,还可以一箭多雕。
现在所有雕在一条直线上从左到右排列,但是他们的高度不同。而小明想要把他们都射下来。小明使用的是一种特殊的弓箭,他可以将弓箭射到任意一个高度为H的雕,当射中一个高度为H的雕后,弓箭的高度会下降到H-1,再从左到右飞行,直到射到高度为H-1的大雕,再降低1的高度,直到飞出大雕的队列。
由于弓箭数量有限,小明想要知道,最少用多少的弓箭,就可以射下所有的大雕。

输入

第一行一个整数,n表示直线上的大雕数量。
第二行n个整数,表示从左到右每个大雕的高度。

输出

输出一个整数,表示最少用的弓箭数量。

样例输入

【样例1】
5
2 1 5 4 3
【样例2】
5
1 2 3 4 5
【样例3】
5
4 5 2 1 4

样例输出

【样例1】
2
【样例2】
5
【样例3】
3

数据范围

30%的数据,n<=5000, 大雕的高度<=10000
70%的数据,n<=1000000, 大雕的高度<=1000000
100%的数据,n<=1000000, 大雕的高度<=1000000000。

思路

第一眼看到的时候,想当然的以为这道题应该是读入全部数据后,从头开始遍历大雁高度,之后从当前位置查找有没有h-1高度的大雁,存在则继续向后找,不存在则箭数++。这样的思路没有问题,但如果选择生硬的使用STL解决,回避不了TLE的命运。
(如果的确有用STL的AC代码还烦请指点一下)
看了一篇博客中的代码后思路清晰了一些,为代码补全了一些注释与自己的理解。
1e9的数据,1e6的询问,应该做下离散化,之后维护了一个有关同一高度的箭编号的链表(毕竟大雁的高度是可以重复的),这段读了很久,所以维护链表的每行代码都添加了注释

AC代码

#include<cstdio>
#include<iostream>
#include<algorithm>
 
using namespace std;
int n, x, h, now, ans;
int a[1000005], p[1000005], c[1000005];
int head[1000005], Next[1000005];
struct ty {
    int v, id;
} b[1000005];
 
bool cmp(ty x, ty y) {
    return x.v < y.v;
}
 
int main() {
    cin >> n;
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
        b[i].v = a[i];
        b[i].id = i;
    }
    sort(b + 1, b + n + 1, cmp);
    b[0].v = -1e9;
    for (int i = 1; i <= n; i++) {
        if (b[i].v != b[i - 1].v) x++;//去重 即重复的v不在p数组内分配位置
        p[x] = b[i].v; //离散化后的x对应的真实值
        c[b[i].id] = x; //c存下每个水平位置所对应的大雁的相对高度(即离散化后的结果)
    }
    //b数组完成使命
    for (int i = 1; i <= x; i++) head[i] = -1;
    for (int i = 1; i <= n; i++) {
        h = c[i]; //h为第一只大雁的相对高度
        if (h + 1 <= x //找相对高度+1没超过最大值x
            && p[h + 1] == a[i] + 1 //这两个相对高度映射回两个真实高度,之间也只差1
            && head[h + 1] != -1) //相对高度h+1高度处有根编号为head[h+1]的箭尚未落下
        {
            now = head[h + 1]; //用now存储当前这根箭的编号
            head[h + 1] = Next[head[h + 1]];
            //把h+1高度的其他(另一根)箭的编号放到head[h+1](now当然也是h+1高度上一支箭)
            Next[now] = head[h]; //先把h高度已有的箭的标号存储至next[now]中
            head[h] = now; //现在变为相对高度为h处有一根编号为now的箭尚未落下
        } else {
            ans++; //需要额外的一支箭
            Next[ans] = head[h]; //先把h高度已有的箭的标号提前转存在next[ans]中
            head[h] = ans; //相对高度为h处有一支编号为ans的箭
        }
    }
    cout << ans;
    return 0;
}

AC代码引用自:一箭多雕
AC代码作者:ACTY

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值