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 ...
随机推荐
- POJ 3468 A Simple Problem with Integers 【线段树】
题目链接 http://poj.org/problem?id=3468 思路 线段树 区间更新 模板题 在赋初始值的时候,按点更新区间就可以 AC代码 #include <cstdio> ...
- javascript;json数据,js转换日期方法。
接收json数据,日期格式为:"\/Date(1414078309687)\/" var value = "/Date(1414078309687)/"; va ...
- Understanding When to use RabbitMQ or Apache Kafka
https://content.pivotal.io/rabbitmq/understanding-when-to-use-rabbitmq-or-apache-kafka How do humans ...
- ETL应用:一种一次获取一个平台接口文件的方法
ETL应用场景中,若对端接口文件未能提供,任务会处于循环等待,直到对端提供为止,该方法极大的消耗了系统资源.为此想到了一种方法,一次获取一个平台的文件,实现思路如下: 1.第一次获取对端平台提供目录下 ...
- Shell编程之while循环和until循环
一.当型和直到型循环 1.while循环语句 while < 条件表达式 > do 指令... done while循环执行流程对应的逻辑图 2.until循环语句 until < ...
- pearson相关分析在R中的实现
三个相关性函数: cor():R自带的,输入数据可以是vector,matrix,data.frame,输出两两的相关系数R值 cor.test():R自带的,输入数据只能是两个vector,输出两个 ...
- INSPIRED启示录 读书笔记 - 第10章 管理上司
十条经验 1.为项目波动做好准备:用项目波动代指让你心烦意乱的各种返工.计划变更.不要企图消灭项目波动,但是可以尽量降低其负面影响.方法是提高警惕,记录工作进度,掌握项目波动的规律,寻找对策.制订项目 ...
- flume 使用遇到问题及解决
1. ../flume/fchannel/spool/data/ 目录下发生缓存文件积压 可能原因:同一时间同一客户端下向两个监控目录mv文件:或同一时间多个客户端向服务端上传文件 2.清空../fl ...
- 用vim写python脚本的自动缩进格式设置
- python统计代码行数
以前写了一个java的统计代码行数的小程序,最近在看python,于是就参考前辈的代码,写了一个统计文件夹下面各种程序的代码的小程序,这里贴出来供大家参考 参考链接: https://gist.git ...