BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)
dp进阶之CDQ分治优化dp。
前置技能:dp基本功底,CDQ分治,树状数组。
问题等价于求二维最长上升子序列,是一个三维偏序问题(时间也算一维)。
设$dp[i]=(l,x)$为以第i枚导弹结尾的最优状态,$l$代表最长上升子序列长度,$x$代表长度为l的最长上升子序列数量,则$(l_0,x_0)$比$(l_1,x_1)$更优当且仅当$l_0>l_1$或($l_0=l_1$且$x_0>x_1$)。(实际上在转移的过程中,第二个条件没什么用)
根据题意有状态转移公式:$dp[i]=\left\{\begin{matrix}\begin{aligned}&(dp[j].l+1,dp[j].x),dp[j].l>dp[i].l\\ &(dp[j].l,dp[i].x+dp[j].x),dp[j].l=dp[i].l\end{aligned}\end{matrix}\right.$,要求$p[j].i<p[i].i,p[j].x<=p[i].x,p[j].y<=p[i].y$。
这样,最长上升子序列的长度就比较容易算了。可每枚导弹被选中的概率呢?等于导弹所在的最长上升子序列的数量/最长上升子序列的总数量,这就需要计算出每个导弹所在的最长上升子序列的个数。计算方法是对导弹正反各求一次dp数组,即分别算出以每枚导弹为起点和终点的最长上升子序列的长度l和数量x,每个导弹所在的最长上升子序列的个数就是两个x的乘积(如果两个l之和为最长上升子序列长度+1的话),否则为0。最长上升子序列的总数为所有导弹所在的最长上升子序列的个数之和/最长上升子序列长度。
由于数据量是5e4的,直接转移复杂度是$O(n^2)$的显然会超时。这时CDQ分治的作用就体现了,可以将复杂度优化到$O(nlog^2n)$。
首先把所有的导弹按照时间顺序排序(输入顺序就是),保证只发生从左边向右边的状态转移。
接下来就要保证x从小到大转移了。对x排序的话显然是会破坏时间顺序的,怎么办?将序列一分为二,对左右两部分的x值分别排序,只计算左半部分向右半部分的转移就行了。这个方法可以递归进行,执行的顺序为:解决左半部分的转移->计算从左半部分向右半部分的转移->解决右半部分的转移。
还剩下一维y怎么处理?再加个树状数组就行了。由于我们只关心y值的相对大小,而不关心它的绝对大小,所以可以离散化(注意下标要从1开始,为了使树状数组能够处理)。这个树状数组的更新过程和一般的树状数组的更新过程有所不同,更新的值是一个二元组(l,x),对l要取最值,对x要累加,即要同时发挥树状数组的维护区间最值和累加功能,并且要新增一个clr函数来撤销之前的更新操作(暴力memset太浪费时间)。
具体细节见代码实现。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef double db;
const int N=5e4+,inf=0x3f3f3f3f;
struct P {
int i,x,y;
bool operator<(const P& b)const {return x<b.x;}
} p[N],p2[N];
struct D {int l; db x;} c[N],dp[][N];
void upd(D& dp,D ad) {
if(dp.l<ad.l)dp.l=ad.l,dp.x=ad.x;
else if(dp.l==ad.l)dp.x+=ad.x;
}
int n,b[N],m;
int lowbit(int x) {return x&-x;}
void add(int u,D x) {for(; u<=m; u+=lowbit(u))upd(c[u],x);}
D get(int u) {D ret= {,}; for(; u; u-=lowbit(u))upd(ret,c[u]); return ret;}
void clr(int u) {for(; u<=m; u+=lowbit(u))c[u]= {,};}
db ans[N]; void CDQ(int l,int r,int f) {
if(l==r) {upd(dp[f][p[l].i], {,}); return;}
int mid=(l+r)>>;
CDQ(l,mid,f);
for(int i=l; i<=r; ++i)p2[i]=p[i];
sort(p2+l,p2+mid+),sort(p2+mid+,p2+r+);
int L,R;
for(R=mid+,L=l; R<=r; ++R) {
for(; L<=mid&&p2[L].x<=p2[R].x; ++L)add(p2[L].y, {dp[f][p2[L].i].l,dp[f][p2[L].i].x});
D t=get(p2[R].y);
upd(dp[f][p2[R].i], {t.l+,t.x});
}
for(int i=l; i<L; ++i)clr(p2[i].y);
CDQ(mid+,r,f);
} int main() {
scanf("%d",&n);
for(int i=; i<n; ++i)scanf("%d%d",&p[i].x,&p[i].y),p[i].i=i;
for(int i=; i<n; ++i)b[i]=p[i].y;
sort(b,b+n);
m=unique(b,b+n)-b;
memset(dp,,sizeof dp);
memset(c,,sizeof c);
for(int i=; i<n; ++i)p[i].x=-p[i].x,p[i].y=m-(lower_bound(b,b+m,p[i].y)-b);
CDQ(,n-,);
for(int i=; i<n; ++i)p[i].x=-p[i].x,p[i].y=m-p[i].y+;
reverse(p,p+n);
CDQ(,n-,);
D mx= {,};
for(int i=; i<n; ++i)upd(mx, {dp[][i].l+dp[][i].l-,dp[][i].x*dp[][i].x});
mx.x/=mx.l;
for(int i=; i<n; ++i)ans[i]=dp[][i].l+dp[][i].l-==mx.l?dp[][i].x*dp[][i].x/mx.x:;
printf("%d\n",mx.l);
for(int i=; i<n; ++i)printf("%f%c",ans[i]," \n"[i==n-]);
return ;
}
BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)的更多相关文章
- BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】
题目 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其 ...
- BZOJ 4553 [Tjoi2016&Heoi2016]序列 ——CDQ分治 树状数组
考虑答案的构成,发现是一个有限制条件的偏序问题. 然后三个维度的DP,可以排序.CDQ.树状数组各解决一维. #include <map> #include <cmath> # ...
- [BZOJ2244]:拦截导弹(DP+CDQ分治+树状数组)
题目传送门 题目描述 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于 ...
- BZOJ 2683: 简单题(CDQ分治 + 树状数组)
BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ ...
- BZOJ 1176 Mokia CDQ分治+树状数组
1176: [Balkan2007]Mokia Time Limit: 30 Sec Memory Limit: 162 MBSubmit: 1854 Solved: 821[Submit][St ...
- BZOJ 2683 简单题 cdq分治+树状数组
题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...
- 【bzoj2225】[Spoj 2371]Another Longest Increasing CDQ分治+树状数组
题目描述 给定N个数对(xi, yi),求最长上升子序列的长度.上升序列定义为{(xi, yi)}满足对i<j有xi<xj且yi<yj. 样例输入 8 1 3 3 2 1 1 4 5 ...
- 【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+树状数组
[BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能 ...
- 【bzoj3262】陌上花开 CDQ分治+树状数组
题目描述 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa&g ...
随机推荐
- C#托管代码 CLR
托管代码 是直接编译成机器码,而是编译成中间语言 IL,由 CLR 托管运行. 托管代码就是把底层的一些操作(如内存的读取,释放)全都封装起来了,把有关内存管理的操作全都由CLR来管理, C#使用垃圾 ...
- CENTOS 搭建SVN服务器(附自动部署到远程WEB)
安装subversion服务端 # 安装 yum install -y subversion # 测试是否安装成功 如果显示了版本信息则表示安装成功 svnserve --version;sleep ...
- json教程系列(4)-optXXX方法的使用
在JSONObject获取value有多种方法,如果key不存在的话,这些方法无一例外的都会抛出异常.如果在线环境抛出异常,就会使出现error页面,影响用户体验,针对这种情况最好是使用optXXX方 ...
- pagination结合ajax
function getContent(page,Id){ $.ajax({ type:'get', url:'www.baidu.com', dataType:'jsonp', data:{ }, ...
- INSPIRED启示录 读书笔记 - 第15章 特约用户
产品开发伙伴 为了解决两个问题——既深入洞察目标用户的需求,又赢得用户对产品的推荐,建议征集特约用户协助完成产品研发 在项目的开始阶段物色至少六位积极.活跃.乐于分享的目标户,要求是他们在产品的目标用 ...
- [RK3288][Android6.0] TS-ADC驱动流程小结【转】
本文转载自:https://blog.csdn.net/kris_fei/article/details/55045936 Platform: RK3288OS: Android 6.0Kernel: ...
- nginx面试要点
首先列出一些面试题目包括nginx和redis的. 1..nginx 框架是怎样的 2. nginx负载均衡的算法怎么实现的,懵逼,说没看过 . nginx 的 upstream目前支持 4 种方式 ...
- Kafka高可用环境搭建
Apache Kafka是分布式发布-订阅消息系统,在 kafka官网上对 kafka 的定义:一个分布式发布-订阅消息传递系统. 它最初由LinkedIn公司开发,Linkedin于2010年贡献给 ...
- springcloud-搭建服务注册中心
创建服务注册中心 1.创建一个springboot 命名为eureka-server 1)添加Eureka依赖 pom.xml <?xml version="1.0" enc ...
- HBase-集群状态信息
代码如下 package com.hbase.HBaseAdmin; import java.io.IOException; import java.util.Collection; import j ...