昨天晚上看蓝书,看到了LIS问题的优化解法。

是比O(n方)更快的解法,实际上是一个常数优化。

先讲一下朴素的解法:

一个集合a,a[i]是第i个元素。设dp[i]为以编号为i的元素结尾的最长不上升子序列。

找到状态转移:

dp[i] = max{dp[j]}+1  (j < i && a[j] >= a[i])

这样的解法是O(n方)的。

如何让它更快,我们可以先推出一个结论:

长度相同的序列,最后元素或者最前元素后于另一个序列的最后元素或者最前元素的序列更优。

证明:

dp[i]是编号i元素结尾的最长不上升子序列,所以这个子序列的结尾是编号i。

前一个导弹越高,更可能拦截下一个导弹,所以a[i]越大越好。

在当前最长不上升子序列中,只有最后一个元素决定了下一个导弹是否被拦截,由上上一行得到子序列中(不上升)最后一个元素越大越好。

所以,我们的命题就变成了:长度相同的子序列(不上升),越往后,子序列的最后一个元素越大。

因为如果较往后的序列一定选中了较往前的序列中没有的数字,而且它的最后一个元素显然不可能被前序列选取,由于他们长度相同,所以它也一定舍弃了前序列的某些数字。

因为它们都是不上升子序列,由此可推出舍弃的元素一定小于后序列的最后一个元素(和某些元素),而最后一个元素(不管哪个序列)都一定是这个序列中最小的。

又因为前序列最后元素大于后序列某些元素,且后序列最后元素是其序列中最小的。

所以后序列最后元素大于前序列最后元素,证毕。

既然我们知道每一个长度的子序列在每个状态中都有最优解,我们就设g[i]是长度为i的最优子序列结尾的编号。

通过上述的证明,我们知道g[i]是长度为i的最优子序列(的结尾)。

然后使用一个变量t来记录当前求出的最长不上升子序列。

所以,从g[t],g[t-1],g[t-2] ... g[1] 遍历,一旦找到其中一个结尾高于当前元素(i),我们就可以得到dp[i]。这时候,因为我们的i一定比g[dp[i]]大,所以我们更新g[dp[i]]。

然后通过dp[i]来更新t,t = max(t,dp[i])。

这样,优化就完成了。

可以注意到这道题还有”第二问“。

使用 Dilworth定理:偏序集的最少反链划分数等于最长链的长度

虽然并不是很明白是怎么回事,但是它将第二问转化为求一个最长上升子序列的长度。(将这些导弹划分为一些不上升子序列)

还有一种理解方法是将这些导弹划分为一些不上升子序列(一次一次地在当前集中选出最长子序列,然后去掉这个序列)

这样,每两个个序列之所以被分为每两个序列,是因为它们之间不满足单调不升。所以,可以把每个序列理解成一个元素,这些元素一定是上升的。

又因为这些序列都是不上升子序列,因此除了每个序列上升的元素,其他元素都被排斥在外,不是最长上升子序列的一部分。

这样,我们的问题是要求组数,所以我们只要求其最长上升子序列即可。

至于代码,就很好写了,只需要从前往后递推,对于每个元素都从t到1枚举一遍,找到最长的符合当前情况的最优序列即可。(求不升,上升子序列的代码几乎一样)

代码:

#include<iostream>
#include<vector>
#include<cstdio>
#include<queue>
#include<map>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<set>
#include<cstring>
using namespace std;
typedef long long ll;
const ll INF=;
const int MaxN = ;
int dp[MaxN],g[MaxN],a[MaxN],n,t; inline int Max(int a,int b){
if(a>b) return a;
return b;
}
int main()
{
//freopen("testdata.in","r",stdin);
//freopen("testdata.out","w",stdout);
while(~scanf("%d",&a[++n]));
n--;
//scanf("%d",&n);
//for(int i = 1;i <= n; i++) scanf("%d",&a[i]); t = ;
dp[] = ;
for(int i = ;i <= n; i++){
dp[i] = ;
for(int j = t;j >= ; j--){
if(a[i] <= a[g[j]]){
dp[i] = dp[g[j]]+; break;
} }
t = Max(t,dp[i]);
g[dp[i]] = i;
}
printf("%d\n",t);
t = ;
for(int i = ;i <= n; i++){
dp[i] = ;
for(int j = t;j >= ; j--){
if(a[i] > a[g[j]]){
dp[i] = dp[g[j]] + ; break;
} }
t = Max(t,dp[i]);
g[dp[i]] = i;
}
printf("%d",t);
return ;
}

Code

【LIS】Luogu P1020 导弹拦截的更多相关文章

  1. luogu P1020 导弹拦截 x

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

  2. Luogu P1020 导弹拦截

    传送门 这道题信息量好大啊 1.Dilworth定理 Dilworth定理:对于一个偏序集,最少链划分等于最长反链长度. Dilworth定理的对偶定理:对于一个偏序集,其最少反链划分数等于其最长链的 ...

  3. Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列)

    Luogu 1020 导弹拦截(动态规划,最长不下降子序列,二分,STL运用,贪心,单调队列) Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺 ...

  4. codevs1044 拦截导弹==洛谷 P1020 导弹拦截

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

  5. p1020导弹拦截

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

  6. 【题解】P1020 导弹拦截

    [题解]P1020 导弹拦截 从n^2到nlogn 第二问就是贪心,不多说 第一问: 简化题意:求最长不下降子序列 普通n^2: for (int i = 1; i <= n; i++) for ...

  7. P1020 导弹拦截(LIS)

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

  8. 洛谷 P1020导弹拦截题解

    洛谷链接:https://www.luogu.org/problem/P1020 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到 ...

  9. 洛谷 P1020 导弹拦截(dp+最长上升子序列变形)

    传送门:Problem 1020 https://www.cnblogs.com/violet-acmer/p/9852294.html 讲解此题前,先谈谈何为最长上升子序列,以及求法: 一.相关概念 ...

随机推荐

  1. IIS+php服务器无法上传图片解决办法

    查找网上资料,发现php.ini下面有2个地方关于上传的配置: file_uploads = On  这里设置是否允许HTTP上传,默认应该为ON的 ;upload_tmp_dir=  这里设置上传文 ...

  2. JAVA基础——设计模式之简单工厂模式

    在阎宏博士的<JAVA与模式>一书中开头是这样描述简单工厂模式的:简单工厂模式是类的创建模式,又叫做静态工厂方法(Static Factory Method)模式.简单工厂模式是由一个工厂 ...

  3. python3+beautifulSoup4.6抓取某网站小说(三)网页分析,BeautifulSoup解析

    本章学习内容:将网站上的小说都爬下来,存储到本地. 目标网站:www.cuiweijuxs.com 分析页面,发现一共4步:从主页进入分版打开分页列表.打开分页下所有链接.打开作品页面.打开单章内容. ...

  4. Cloudera’s Distribution Including Apache Hadoop(CDH)安装过程

    文档地址:https://www.cloudera.com/documentation.html                 https://www.cloudera.com/documentat ...

  5. 笔试算法题(58):二分查找树性能分析(Binary Search Tree Performance Analysis)

    议题:二分查找树性能分析(Binary Search Tree Performance Analysis) 分析: 二叉搜索树(Binary Search Tree,BST)是一颗典型的二叉树,同时任 ...

  6. <Spring Cloud>入门一 Eureka Server

    1.搭建父工程 主要是添加版本依赖,此处版本是: spring-boot  : 2.0.8.RELEASE spring-cloud : Finchley.SR2 <?xml version=& ...

  7. 学习Python一年,基础忘记了,看看面试题回忆回议,Python面试题No3

    这边有几个面试题,好棒 第1题:你如何管理不同版本的代码? git,svn两个都要说到,github,码云也要提及,面试官想要的就是版本管理工具,你只要选择一个你熟悉的,疯狂的说一通就可以了,最好说一 ...

  8. Java反射机制(Reflect)解析-----https://www.cnblogs.com/fzz9/p/7738381.html

    Java反射机制(Reflect)解析-----https://www.cnblogs.com/fzz9/p/7738381.html

  9. 1001. A+B Format (20) (%0nd)

    1001. A+B Format (20) 时间限制 400 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue Calculate ...

  10. P1072 Hankson的趣味题

    #include<iostream> #include<cstdio> #include<cstring> #include<cmath> #inclu ...