拦截导弹nlogn解法
题目
题目描述
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
输入导弹依次飞来的高度(雷达给出的高度数据是\(\le 50000\)的正整数),计算这套系统最多能拦截多少导弹,如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
输入格式
\(1\)行,若干个整数(个数\(\le 100000\))
输出格式
\(2\)行,每行一个整数,第一个数字表示这套系统最多能拦截多少导弹,第二个数字表示如果要拦截所有导弹最少要配备多少套这种导弹拦截系统。
算法分析
我们先看一个例子。
例子
输入数据
10
0 192 100 91 149 146 159 137 17 188
定义三个变量
opt[i]:表示长度为i的不升序列的末位数字最大为opt[i]
opt_n:当前最长不升序列的长度
f[i]:动态规划计算,以第i个导弹结尾的最长不升序列的长度为f[i]
定义一个函数
int s(int i):二分查找最大的k使得opt[k]>=h[i]
初始值
memset(opt,0,sizeof(opt));
opt[1]=h[1];f[1]=1;
状态转移方程
\(f[i]=k+1,k=max\{k\mid opt[k]\ge h[i]\}\)
如果\(\{k\mid opt[k]\ge h[i]\}=\varnothing\)则\(k=0\)
遍历
代码
for(int i=2;i<=n;++i){
    k=s(i);f[i]=k+1; //求最大的k使得opt[k]>=h[i],则f[i]=k+1
    if(f[i]<=opt_n){ //如果f[i]不超过opt_n,则考虑更新opt[f[i]]
        if(opt[f[i]]<h[i]) opt[f[i]]=h[i];
    }else opt_n++,opt[opt_n]=h[i];
}
手算理解(建议先看总结,看不懂再看这里):
- 当 - i=2,h[i]=192,没有- 1<=k<=n使得- opt[k]>192,那么- k=s(i)=0,- f[i]=0+1=1。
 此时- f[i]>opt_n=0,即 当前方案长度 超过了- opt中已知的最长序列的长度,则需要更新- opt(发现了更长的不升序列,补到- opt中)。- opt_n++; //opt_n=1
 opt[opt_n]=h[i] //opt[1]=192
 
- 当 - i=3,h[i]=100,存在最大的- k=1使得- opt[k]=192>100,那么- f[i]=k+1=2。
 此时- f[i]>opt_n,更新- opt。- opt_n++; //opt_n=2
 opt[opt_n]=h[i] //opt[2]=100
 
- 当 - i=4,h[i]=91,存在最大的- k=2使得- opt[k]=100>91,那么- f[i]=k+1=3。
 此时- f[i]>opt_n,更新- opt。- opt_n++; //opt_n=3
 opt[opt_n]=h[i] //opt[3]=91
 
- 当 - i=5,h[i]=149,存在最大的- k=1使得- opt[k]=192>149,那么- f[i]=1+1=2。
 此时- f[i]<opt_n,即 当前序列长度 小于- opt中已知的最长序列的长度;也就是说,前面已经有过长度相同的不升序列。
 需要判断此时- h[i]是否大于- opt[f[i]],因为- opt要存最大的末位数字。- if(opt[f[i]]<h[i]) //opt[f[i]]=opt[2]=100<149
 opt[f[i]]=h[i]; //opt[2]=149
 
依此类推,之后的操作直接给出:
i=6,f[i]=3
opt[1]=192|opt[2]=149|opt[3]=146|opt[4]=  0|opt[5]=  0|opt[6]=  0|
i=7,f[i]=2
opt[1]=192|opt[2]=159|opt[3]=146|opt[4]=  0|opt[5]=  0|opt[6]=  0|
i=8,f[i]=4
opt[1]=192|opt[2]=159|opt[3]=146|opt[4]=137|opt[5]=  0|opt[6]=  0|
i=9,f[i]=5
opt[1]=192|opt[2]=159|opt[3]=146|opt[4]=137|opt[5]= 17|opt[6]=  0|
i=10,f[i]=2
opt[1]=192|opt[2]=188|opt[3]=146|opt[4]=137|opt[5]= 17|opt[6]=  0|
总结
而对于同长度的序列,要判断h[i]是否能够接在其后,当然只要判断这些序列中最大的末位数字是否比h[i]大。大了就一定可以,小了就一定不可以。所以opt[i]存的是长度为i的不升序列的末位最大数字。
于是,计算f[i]只要在k=1..i-1中找满足opt[k]>=h[i]的尽可能大的k,接在其后,新的序列长度就为k+1。
而opt数组是递减的(反证法:因为每个时刻opt[i]都存长度为i的不升序列的末位最大数字,若i<j且opt[i]<opt[j],那么为什么opt[i]的值不能为opt[j]这个序列中的第i个元素呢?),所以可以用二分查找最大的k。
在上面这些操作后,时间复杂度就顺利地降成了O(nlogn)。(´▽` )
附:完整代码
#include<cstdio>
#define reg register
using namespace std;
int n,h[100001],f[100001],opt[100001],opt_n;
int s(int i){
    //二分查找最大的k使得opt[k]>=h[i]
    int l=1,r=n,m;
    while(l<=r){
        m=(l+r)/2;
        if(opt[m]>=h[i]){
            if(m+1<=r && opt[m+1]>=h[i])
                l=m+1;
            else return m;
        }else r=m-1;
    }
    return 0;
}
void dp(){
    //opt[i]:长度是i的最长不升子序列所有子串中末尾最大的那个数,
    //根据这个数字,我们可以容易知道,
    //只要当前考察的这个数比opt[i]小,那么当前这个数一定能通过opt[i]构成一个长度为i+1的下降子序列。
    int k;
    opt_n=1;
    opt[1]=h[1];f[1]=1;
    for(reg int i=2;i<=n;++i){
        k=s(i);f[i]=k+1; //求最大的k使得opt[k]>=h[i],则f[i]=k+1
        if(f[i]<=opt_n){ //如果f[i]不超过opt_n,则考虑更新opt[f[i]]
            if(opt[f[i]]<h[i]) opt[f[i]]=h[i];
        }else opt_n++,opt[opt_n]=h[i];
        /*--debug--
        printf("\n\ni=%d,f[i]=%d\n",i,f[i]);
        for(reg int x=1;x<=6;++x)printf("opt[%d]=%3d|",x,opt[x]);
        */
    }
}
int main(){
    scanf("%d",&n);
    for(reg int i=1;i<=n;++i)scanf("%d",&h[i]);
    dp();
    printf("%d",opt_n);
}
拦截导弹nlogn解法的更多相关文章
- 1260:【例9.4】拦截导弹(Noip1999)
		题目来源:http://ybt.ssoier.cn:8088/problem_show.php?pid=1260 1260:[例9.4]拦截导弹(Noip1999) 时间限制: 1000 ms ... 
- 拦截导弹类问题 (Codevs4888零件分组POJ1065Wooden Sticks)(LIS及其覆盖问题)
		拦截导弹 题意:求最长不上升子序列长度:求一个序列最少分成几个非增子序. 第一问易求,已知序列a,令f[i]为a前i个元素的最长非增子序的长度,则有 f[i]=max{f[i],f[j]+1} (1& ... 
- codevs1409 拦截导弹2
		[问题描述]一场战争正在 A 国与 B 国之间如火如荼的展开.B 国凭借其强大的经济实力开发出了无数的远程攻击导弹,B 国的领导人希望,通过这些导弹直接毁灭 A 国的指挥部,从而取得战斗的胜利!当然, ... 
- nyoj814_又见拦截导弹_DP
		又见拦截导弹 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 大家对拦截导弹那个题目应该比较熟悉了,我再叙述一下题意:某国为了防御敌国的导弹袭击,新研制出来一种导弹拦 ... 
- 【动态规划】拦截导弹_dilworth定理_最长递增子序列
		问题 K: [动态规划]拦截导弹 时间限制: 1 Sec 内存限制: 256 MB提交: 39 解决: 10[提交][状态][讨论版] 题目描述 张琪曼:“老师,修罗场是什么?” 墨老师:“修罗是 ... 
- ACM题目————又见拦截导弹
		描述 大家对拦截导弹那个题目应该比较熟悉了,我再叙述一下题意:某国为了防御敌国的导弹袭击,新研制出来一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:它的第一发炮弹能够到达任意的高度,但是以后每一发炮 ... 
- nyoj------79拦截导弹
		拦截导弹 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到 ... 
- 百练_2945 拦截导弹(DP)
		描述 某国为了防御敌国的导弹袭击,开发出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度.某天,雷达捕捉到敌国的导弹来袭 ... 
- nyoj 79 拦截导弹
		拦截导弹 时间限制:3000 ms | 内存限制:65535 KB 难度:3 描述 某国为了防御敌国的导弹袭击,发展中一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到 ... 
随机推荐
- 性能测试yslow
			YSlow YSlow可以对网站的页面进行分析,并告诉你为了提高网站性能,如何基于某些规则而进行优化. YSlow可以分析任何网站,并为每一个规则产生一个整体报告,如果页面可以进行优化,则YSlow会 ... 
- javascript 缩写技巧
			19种JS高(炫)效(技)缩写法 https://segmentfault.com/a/1190000011229633 
- 飞机躲避炮弹---java
			最近闲来无事,花了一天多的时间写了一个小游戏,虽然说游戏本身很无聊吧,但是自己也从这个过程中学到了许多东西...分享一下. 代码内容自行理解吧... 层次结构: package cn.sxt.game ... 
- html的空格和换行显示
			一.HTML 代码中的所有连续的空格或空行(换行)都会被显示为一个空格,不管是内容还是标签之间. 二.当我们想让它们在同一行连续显示时,就让所有的代码之间没有空格,也不要换行. 三.当我们想要显示连续 ... 
- Cookie:解决HTTP协议无保存状态
			客户端 Cookie会根据从服务器端发送的相应报文内一个叫Set-Cookie的首部字段信息,通知客户端保存Cookie.当下次客户端再往该服务器发送请求时,客户端会自动在请求报文中加入Cookie值 ... 
- shiro 角色与权限的解读
			1.为什么 shiro 有了<角色>后,还要设置<角色权限>呢?(问题) 思考:设置好角色了,那么就代表什么操作都可以执行了吗? 理解:如果上边回答是的话,那么只是<角色 ... 
- File 文件
			1 File 概述 文件:file目录:directory路径:path File类静态成员变量: pathSeparator:与系统有关的路径分隔符,为了方便,它被表示为一个字符串separator ... 
- 流控制、FlowControl
			这个选项基本上所有网卡都会有,但是叫法会有些差别,比如Realtek网卡叫做流控制,Intel网卡叫做流程控制,还有一些网卡选项干脆是英文的,叫做FlowControl,很多交换机上也有这个功能,也叫 ... 
- pandas处理时间序列(2):DatetimeIndex、索引和选择、含有重复索引的时间序列、日期范围与频率和移位、时间区间和区间算术
			一.时间序列基础 1. 时间戳索引DatetimeIndex 生成20个DatetimeIndex from datetime import datetime dates = pd.date_rang ... 
- [pat]1068 Find More Coins
			满背包问题,把体积和价值看成相等的.用滚动数组优化,然后额外开辟一个choice数组来记录每次的选择,然后回溯打印.因为要按字典序,先把价值进行排序.假如选最小的商品能装满m的话,那就把判断条件改成大 ... 
