题意

题目描述

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

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

输入格式

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

输出格式

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

输入输出样例

输入 #1

389 207 155 300 299 170 158 65

输出 #1

6

2

说明/提示

为了让大家更好地测试n方算法,本题开启spj,n方100分,nlogn200分

每点两问,按问给分

分析

LIS的两种优化(好像不用这个做也行....但我不会呀)

问题1: 显然,是求最长不上升子序列

问题2: 分析一下, 问需要多少个系统才能把导弹全部拦截。 一个系统所能拦截的导弹是“不上升的”, 所以我们手算一下样例, 发现有转折的地方(“155”->“300”), 是必须要多加一个系统的。 而“207”->“300”其实也是一个转折, 但上一个加的系统就能够拦截到“207”了, 所以,我们再多造几组数据,发现,这个就是一个最长上升子序列。(其实我也不会...)

这里主要讲讲它的优化, 我们看见题目明确的要nlogn算法, LIS的nlogn算法(我知道的)有树状数组优化和二分+贪心+类似栈的东西

树状数组优化: 因为它只添加,而且t数组也是只增不减的, 所以可以用树状数组做。 注意实现的细节: 求以x结尾的最长上升子序列的时候, 不能把x算上, 因为可能在之前出现过x。

  1. #include<cstdio>
  2. #include<string.h>
  3. #include<algorithm>
  4. using namespace std;
  5. #define lowbit(x) (x&-x)
  6. const int MAX = 50000+9;
  7. const int N = 100000+9;
  8. int ft[MAX], mx, num;
  9. int a[N];
  10. void add1(int x, int k) {while(x <= MAX) ft[x] = max(ft[x], k), x += lowbit(x);}
  11. int query1(int x) {
  12. int mx = -1;
  13. x -= 1;//LIS:是上升! 所以不包括相等
  14. while(x) {
  15. mx = max(ft[x], mx);
  16. x -= lowbit(x);
  17. }
  18. return mx;
  19. }
  20. void add2(int x, int k) {while(x) ft[x] = max(ft[x], k), x -= lowbit(x);}
  21. int query2(int x) {//最长不上升序列: 可以相等
  22. int mx = -1;
  23. while(x <= MAX) {
  24. mx = max(ft[x], mx);
  25. x += lowbit(x);
  26. }
  27. return mx;
  28. }
  29. int main() {
  30. int n = 0;
  31. while(scanf("%d", &a[++n]) == 1) ;
  32. --n;//多读了一个
  33. mx = 1;
  34. for(int i = 1; i <= n; i++) {
  35. ft[a[i]] = query2(a[i]) + 1;
  36. mx = max(ft[a[i]], mx);
  37. add2(a[i], ft[a[i]]);
  38. }
  39. printf("%d\n", mx);
  40. memset(ft, 0, sizeof(ft));
  41. num = 0;
  42. for(int i = 1; i <= n; i++) {//求LIS
  43. ft[a[i]] = query1(a[i]) + 1;
  44. num = max(num, ft[a[i]]);
  45. add1(a[i], ft[a[i]]);
  46. // printf("%d ", ft[a[i]]);
  47. }
  48. printf("%d", num);
  49. return 0;
  50. }

二分+贪心(这里只给出LIS的二分代码)

其实这个我也不知道为什么能A,有可能是因为我看它的代码的时间比较长, 背下来了吧(不然怎么自己打出来了呢?

定义f[i]: 长度为i的上升子序列的末尾元素的最小值, 贪心的思路, f[i]越小, 我们后面的选择就越多。显然, f是递增的(自己写下数据)

f[1] = a[1], len = 1,(len表示当前的最长长度)

接下来i从2开始向后枚举 如果a[i]>f[len] f[++len]=i;//放到后面 不然每次在f里面二分查找第一个大于等于a[i]的数来更新f数组,设它的下标为l

(因为f[l]为第一个大于等于a[i]的数, 所以f[l-1] < a[i], 所以我们是不可以用a[i]更新f[l-1]及l-1以前的, 而我们却可以更新的f[l], 这样改只会使f[l]更小或不变, 也就是使f[l]更优。) (过程: 要是f[mid]<a[i], 那么显然f[mid] 包括 f[mid-1]及以前的都不能更新, 所以l = mid+1。 如果f[mid] >= a[i], 那么l~mid是可能需要更新的,而mid的右边的f[]>a[i], 不能用a[i]更新f[], 所以r = mid)(注: 左闭右开

最后比较大小,f[l]=min(f[l],a[i])

  1. int len = 1;
  2. ft[1] = a[1];
  3. for(int i = 2; i <= n; i++) {//求LIS
  4. if(a[i] > ft[len]) ft[++len] = a[i];
  5. else {
  6. int l = 1, r = len, mid;
  7. while(l < r) {
  8. mid = (l+r)>>1;
  9. if(ft[mid] >= a[i]) r = mid;
  10. //其实如果ft[mid] == a[i], 按理说应该是l=mid,但那样循环不出来;如果这样写的话,l 最后也会拿到正解的
  11. else l = mid+1;
  12. //其实可以反着思考, 既要使二分能循环出来(l = mid+1)又要符合逻辑(ft[mid] < a[i]时 l = mid), 就只能这么写了
  13. }
  14. ft[l] = min(ft[l], a[i]);
  15. }
  16. }
  17. printf("%d", len);

luoguP1020 导弹拦截的更多相关文章

  1. LuoguP1020 导弹拦截 (LIS)

    最长不降和单升 #include <iostream> #include <cstdio> #include <cstring> #include <algo ...

  2. Luogu-P1020(导弹拦截)(DP,LIS ,二分优化)

    Luogu-P1020(导弹拦截)(DP) 题意: 给n(n<=100000) 个数字,求最长不上升子序列的长度和最少的不上升子序列的个数. 分析: 第一问: 求最长不上升子序列有 O(n^2) ...

  3. HDU-1257 导弹拦截系统 http://acm.hdu.edu.cn/showproblem.php?pid=1257

    Problem Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能超过前一发的高 ...

  4. AC日记——导弹拦截 洛谷 P1020 (dp+模拟)

    题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...

  5. 【codevs1044】导弹拦截问题与Dilworth定理

    题目描述 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某 ...

  6. TYVJ P1020 导弹拦截 Label:水

    题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹 ...

  7. bzoj2044: 三维导弹拦截

    Description 一场战争正在A国与B国之间如火如荼的展开. B国凭借其强大的经济实力开发出了无数的远程攻击导弹,B国的领导人希望,通过这些导弹直接毁灭A国的指挥部,从而取得战斗的胜利!当然,A ...

  8. nyoj 79 导弹拦截

    点击打开链接 拦截导弹 时间限制:3000 ms  |  内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发 ...

  9. UESTC_导弹拦截 2015 UESTC Training for Dynamic Programming<Problem N>

    N - 导弹拦截 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit  ...

随机推荐

  1. sql server 字符数据类型

    SQL Server 中字符类型包括varchar.char.text等.主要用于存储字符数据.varchar和char类型的主要区别在于数据填充.例如,一个列名为FirstName且数据类型为var ...

  2. JVM常用参数详解

     JVM整个堆大小=年轻代大小 + 年老代大小 + 持久代大小,在JDK1.8及之后的版本由于永久代被元空间替代,所以jdk1.8中的堆=年轻代大小 + 年老代大小.本文使用的是JDK1.8  1.堆 ...

  3. SQL实用技巧:如何分割字符串

    create function f_split(@c varchar(2000),@split varchar(2)) returns @t table(col varchar(20)) as beg ...

  4. Redis未授权访问利用

    转载:https://www.cnblogs.com/-qing-/p/10978912.html 0x01 kali安装redis 下载 wget http://download.redis.io/ ...

  5. Computer: CMD and use windows system to better

    Xx_Introduction Please protection,respect,love,"China's Internet Security Act"! For learni ...

  6. idea中git分支、合并与使用

    1.分支的新建与合并使用场景介绍 让我们来看一个简单的分支新建与分支合并的例子,实际工作中你可能会用到类似的工作流. 你将经历如下步骤: 开发某个网站. 为实现某个新的需求.问题(#53问题),创建一 ...

  7. Windows自动执行应用程序或脚本(可以通过写bat文件定时关机等)

    1. Windows每天定时执行某个应用程序 1.1 右键我的电脑选择管理,并选择任务计划程序,如下 演示 --- 1.2 创建基本任务 演示 1.3 Windows每天定时关机设置参数 演示 1. ...

  8. 逻辑卷管理器LVM

    逻辑卷管理器LVM •将设备指定为物理卷 • 用一个或者多个物理卷来创建一个卷组 • 物理卷是用固定大小的物理区域(Physical Extent,PE)来定义的 • 在物理卷上创建的逻辑卷是由物理区 ...

  9. win10+Ubuntu16.04双系统下深度学习环境的搭建

    环境零零碎碎地搭了三四天,虽然碰到各种问题,但还是搭建好了,自己整理记录下,同时也算给有需要的人一些指导吧 一.双系统的安装 Win10硬盘管理助手 压缩或者直接利用未使用的空间,空间大小自定,将腾出 ...

  10. Fail-fast

    实际上,java.util.Iterator 的大多数实现都提供了故障快速修复(Fail-fast)的机制 ⎯⎯在利用迭代器遍历某一容器的过程中,一旦发现该容器的内容有所改变,迭代器就会抛出 Conc ...