题目链接

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分治+树状数组优化)的更多相关文章

  1. BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】

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

  2. BZOJ 4553 [Tjoi2016&Heoi2016]序列 ——CDQ分治 树状数组

    考虑答案的构成,发现是一个有限制条件的偏序问题. 然后三个维度的DP,可以排序.CDQ.树状数组各解决一维. #include <map> #include <cmath> # ...

  3. [BZOJ2244]:拦截导弹(DP+CDQ分治+树状数组)

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

  4. BZOJ 2683: 简单题(CDQ分治 + 树状数组)

    BZOJ2683: 简单题(CDQ分治 + 树状数组) 题意: 你有一个\(N*N\)的棋盘,每个格子内有一个整数,初始时的时候全部为\(0\),现在需要维护两种操作: 命令 参数限制 内容 \(1\ ...

  5. BZOJ 1176 Mokia CDQ分治+树状数组

    1176: [Balkan2007]Mokia Time Limit: 30 Sec  Memory Limit: 162 MBSubmit: 1854  Solved: 821[Submit][St ...

  6. BZOJ 2683 简单题 cdq分治+树状数组

    题意:链接 **方法:**cdq分治+树状数组 解析: 首先对于这道题,看了范围之后.二维的数据结构是显然不能过的.于是我们可能会考虑把一维排序之后还有一位上数据结构什么的,然而cdq分治却可以非常好 ...

  7. 【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 ...

  8. 【BZOJ4553】[Tjoi2016&Heoi2016]序列 cdq分治+树状数组

    [BZOJ4553][Tjoi2016&Heoi2016]序列 Description 佳媛姐姐过生日的时候,她的小伙伴从某宝上买了一个有趣的玩具送给他.玩具上有一个数列,数列中某些项的值可能 ...

  9. 【bzoj3262】陌上花开 CDQ分治+树状数组

    题目描述 有n朵花,每朵花有三个属性:花形(s).颜色(c).气味(m),又三个整数表示.现要对每朵花评级,一朵花的级别是它拥有的美丽能超过的花的数量.定义一朵花A比另一朵花B要美丽,当且仅当Sa&g ...

随机推荐

  1. ajax使用formdata 提交excel文件表单到rails解析

    .modal-body .container-fluid .row .col-md-12 1.下载模板文件 = link_to '模板文件' .row .col-md-12 = form_tag '' ...

  2. iOS Autolayout 在tableView scrollView 适用 学习

    1  如何自动适应cell的高度 autolayout  里面 使用 systemLayoutSizeFittingSize 方法 (系统通过 已知的完整的Constraints和view的属性来计算 ...

  3. Hibernate_HelloWord

    Hibernate操作步骤 1.新建项目 2.加jar包 3.写XML配置文件hibernate.cfg.xml 4.写log4j.properties日志文件 5.在MySql数据库中建studen ...

  4. Java底层代码实现多文件读取和写入

    需求: "E:/data/"目录下有四个文件夹,如下: 每个文件夹下有几个.csv文件,如下: 将每个文件夹下的.csv文件合并成一个以该文件夹命名的.csv文件. 做法: 找到& ...

  5. Linux Shell编程 条件判断语法

    if条件判断语句 单分支 if 条件语句 语法格式: if [条件判断式];then 程序 fi 或者 if [条件判断式] then 程序 fi 在使用单分支 if 条件查询时需要注意几点: if ...

  6. matplotlib模块之plot画图

    关于matplotlib中一些常见的函数,https://www.cnblogs.com/TensorSense/p/6802280.html这篇文章讲的比较清楚了,https://blog.csdn ...

  7. JavaWeb Cookie

    1. Cookie 1.1. Cookie概述 Cookie译为小型文本文件或小甜饼,Web应用程序利用Cookie在客户端缓存服务器端文件.Cookie是以键值对形式存储在客户端主机硬盘中,由服务器 ...

  8. iOS_数据存取(二)

    本节内容目录: 一.SQLite3 二.Core Data 一.SQlite3 SQLite3是⼀款开源的嵌入式关系型数据库,可移植性好.易使用.内存开销小SQLite3是⽆类型的,意味着你可以保存任 ...

  9. linux内核调试+qemu+eclipse【转】

    本文转载自:https://blog.csdn.net/WANG__RONGWEI/article/details/54922727 一.调试环境: 在ubuntu16.04下,在虚拟机里边运行的ub ...

  10. Yii和ThinkPHP对比杂谈

    关于ThinkPHP(以下简称TP)和Yii Framework(以下简称Yii)的背景.作者和速度方面就不涉及了.因为速度是一个很复杂的问题,牵扯的因素很多.我不得不承认ThinkPHP是 一个是国 ...