BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)
题意
略…
分析
就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i]表示以iii结尾的最长不降子序列的长度,有f[i]=max(f[j]+1) ( 0≤j<i,hj≤hi,vj≤vi )f[i]=max(f[j]+1)\ (\ 0\le j<i,h_j\le h_i,v_j\le v_i\ )f[i]=max(f[j]+1) ( 0≤j<i,hj≤hi,vj≤vi )那这就是一个三维偏序问题,只需要第一维CDQCDQCDQ,第二维排序,第三维用树状数组维护就行了.
要求概率,再定义g[i]g[i]g[i]表示以iii开始的最长不降子序列的长度.要求g[i]g[i]g[i]就坐标取反从nnn到111再做一次DPDPDP就行了.我们再设[0][0][0]表示序列长度,[1][1][1]表示这个长度的序列的方案.那对于iii点在最长不降子序列上的概率就是 f[i][1]∗g[i][1] ( f[i][0]+g[i][0]−1=LIS )∑1≤j≤nf[j][1] ( f[j][0]=LIS )\frac{f[i][1]*g[i][1]\ (\ f[i][0]+g[i][0]-1=LIS\ )}{\sum_{1\le j\le n} f[j][1]\ (\ f[j][0]=LIS\ )}∑1≤j≤nf[j][1] ( f[j][0]=LIS )f[i][1]∗g[i][1] ( f[i][0]+g[i][0]−1=LIS )分母其实就是总的最长上升子序列数量.
时间复杂度O(nlog2n)O(nlog^2n)O(nlog2n)
第一次写这样的CDQCDQCDQ,感觉好强…(是我太菜)
CODE
其实CDQCDQCDQ分治和树状数组都要离散化,但是标号本来就是1...n1...n1...n,就只用离散化vvv了.
代码还是蛮短的
#include <cctype>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
char cb[1<<15],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
template<class T>inline void read(T &res) {
char ch; int flg = 1; for(;!isdigit(ch=getchar());)if(ch=='-')flg=-flg;
for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0'); res*=flg;
}
const int MAXN = 50005;
int n, bin[MAXN], tot, indx, stk[MAXN];
struct node { //写一个结构体
int x; double y; //方案数要用double不然会溢出
node() { x = y = 0; }
node(int _x, double _y):x(_x), y(_y){}
inline bool operator <(const node &o)const { return x < o.x; }
}T[MAXN];
inline void chkmax(node &A, const node &B) {
if(B < A) return;
if(A < B) A = B;
else A.y += B.y;
}
inline void upd(int x, node val) {
while(x <= tot) {
if(val.x > T[x].x) {
if(!T[x].x) stk[++indx] = x; //第一次修改就进栈
T[x] = val;
}
else if(val.x == T[x].x) T[x].y += val.y;
x += x&-x;
}
}
inline node qsum(int x) {
node res;
while(x) chkmax(res, T[x]), x -= x&-x;
return res;
}
struct Node { int i, h, v; node f; };
inline bool cmp2(const Node &A, const Node &B) { return A.h == B.h ? A.i < B.i : A.h < B.h; }
inline bool cmp(const Node &A, const Node &B) { return A.i < B.i; }
struct CDQ {
Node a[MAXN], tmp[MAXN];
void cdq(int l, int r) {
if(l == r) { if(!a[l].f.x || !a[l].f.y) a[l].f.x = a[l].f.y = 1; return; }
int mid = (l + r) >> 1;
int L = l, R = mid+1;
for(int i = l; i <= r; ++i) //分成左右两边
if(a[i].i <= mid) tmp[L++] = a[i];
else tmp[R++] = a[i];
for(int i = l; i <= r; ++i) a[i] = tmp[i];
cdq(l, mid);
sort(a + l, a + mid + 1, cmp2); L = l;
for(int i = mid+1; i <= r; ++i) {
while(L <= mid && a[i].h >= a[L].h) upd(a[L].v, a[L].f), ++L;
node res = qsum(a[i].v);
if(!res.x) continue;
++res.x, chkmax(a[i].f, res);
}
while(indx) T[stk[indx--]] = node(0, 0); //清零树状数组
cdq(mid+1, r);
}
}dp[2];
int main () {
read(n);
for(int i = 1; i <= n; ++i) {
dp[0].a[i].i = i, read(dp[0].a[i].h), read(dp[0].a[i].v);
dp[0].a[i].h *= -1, dp[0].a[i].v *= -1;
bin[++tot] = dp[0].a[i].v;
}
sort(bin + 1, bin + tot + 1); //只离散化V
tot = unique(bin + 1, bin + tot + 1) - bin - 1;
for(int i = 1; i <= n; ++i) {
dp[0].a[i].v = lower_bound(bin + 1, bin + tot + 1, dp[0].a[i].v) - bin;
dp[1].a[n-i+1].i = n-i+1;
dp[1].a[n-i+1].h = -dp[0].a[i].h;
dp[1].a[n-i+1].v = tot-dp[0].a[i].v+1;
}
sort(dp[0].a + 1, dp[0].a + n + 1, cmp2), dp[0].cdq(1, n);
sort(dp[1].a + 1, dp[1].a + n + 1, cmp2), dp[1].cdq(1, n); //做两次
sort(dp[0].a + 1, dp[0].a + n + 1, cmp);
sort(dp[1].a + 1, dp[1].a + n + 1, cmp); //重排序为 1~n
node Ans;
for(int i = 1; i <= n; ++i)
chkmax(Ans, dp[0].a[i].f);
printf("%d\n", Ans.x);
for(int i = 1; i <= n; ++i)
if(dp[0].a[i].f.x + dp[1].a[n-i+1].f.x - 1 < Ans.x) printf("%.6f ", 0.0);
else printf("%.6f ", dp[0].a[i].f.y*dp[1].a[n-i+1].f.y/Ans.y);
return 0;
}
BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)的更多相关文章
- bzoj 2244: [SDOI2011]拦截导弹 cdq分治
2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 237 Solved: ...
- BZOJ 2244 [SDOI2011]拦截导弹 ——CDQ分治
三维偏序,直接CDQ硬上. 正反两次CDQ统计结尾的方案数,最后统计即可. #include <cstdio> #include <cstring> #include < ...
- BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]
传送门 题意:三维最长不上升子序列以及每个元素出现在最长不上升子序列的概率 $1A$了好开心 首先需要从左右各求一遍,长度就是$F[0][i]+F[1][i]-1$,次数就是$G[0][i]*G[1] ...
- BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治
2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截 ...
- [BZOJ2244][SDOI2011]拦截导弹 CDQ分治
2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec Memory Limit: 512 MB Special Judge Description 某国为了防御敌国的导弹 ...
- bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2244 [题意] 给定n个二元组,求出最长不上升子序列和各颗导弹被拦截的概率. [思路] ...
- BZOJ 2244 [SDOI2011]拦截导弹 (三维偏序CDQ+线段树)
题目大意: 洛谷传送门 不愧为SDOI的duliu题 第一问?二元组的最长不上升子序列长度?裸的三维偏序问题,直接上$CDQ$ 由于是不上升,需要查询某一范围的最大值,并不是前缀最大值,建议用线段树实 ...
- bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)
传送门 题解 看了半天完全没发现这东西和CDQ有什么关系…… 先把原序列翻转,求起来方便 然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a ...
- bzoj 2244: [SDOI2011]拦截导弹
#include<cstdio> #include<iostream> #include<algorithm> #define M 100009 using nam ...
随机推荐
- 数据库连接池——C3P0&Druid(快速入门)
数据库连接池--C3P0&Druid (一) 数据库连接池 每一个事物都有其存在的意义,在初学jdbc的时候,我们建立数据库连接对象后,会对其进行释放,但是数据库连接的建立和关闭是非常消耗资源 ...
- PTA(Advanced Level)1050.String Subtraction
Given two strings S1 and S2, S=S1−S2 is defined to be the remaining string after taking all the char ...
- axios设置请求头内容
axios设置请求头中的Authorization 和 cookie 信息: GET请求 axios.get(urlString, { headers: { 'Authorization': 'Bea ...
- AC自动机fail树上dfs序建线段树+动态memset清空
题意:http://acm.hdu.edu.cn/showproblem.php?pid=4117 思路:https://blog.csdn.net/u013306830/article/detail ...
- python3启航
Python3的基本数据类型 数字 int ,所有功能都放在int里 a1 = 123 a2 = 456 ##int 将字符串转换为数字 a = "123" print(tyep( ...
- Python 闭包、迭代器、生成器、装饰器
Python 闭包.迭代器.生成器.装饰器 一.闭包 闭包:闭包就是内层函数对外层函数局部变量的引用. def func(): a = "哈哈" def func2(): prin ...
- Statefulset的拓扑状态
Statefulset: 实例之间有不对等关系,以及实例对外部数据有依赖关系的应用,就被称为“有状态应用”(Stateful Application). StatefulSet 的设计其实非常容易理解 ...
- 怎样实现跨域AJAX请求发送Cookie
第一步: 服务器必须在Response Header中设置: Access-Control-Allow-Credentials: true 第二步: 客户端发起请求时需要将 xhr.withCrede ...
- 怎样监听HTTP请求的发出与完成
1. 监听HTTP请求发出的事件是: xhr.onloadstart 2. 监听HTTP请求结束的事件是: xhr.onloadend xhr.onloadstart = function() { / ...
- hdu 1506 最大子矩阵面积
//写动态规划的题目 要把主要问题提炼出来 这里的问题就是求area=(j-k+1)*a[i] 如果找到j k是解决这个题目的关键 这里暴力求肯定是要超时的 这里用dp来优化 #include< ...