BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治
2244: [SDOI2011]拦截导弹
Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。
Input
第一行包含一个正整数n,表示敌军导弹数量;
下面 行按顺序给出了敌军所有导弹信息:
第i+1行包含2个正整数hi和vi,分别表示第 枚导弹的高度和速度。
Output
输出包含两行。
第一行为一个正整数,表示最多能拦截掉的导弹数量;
第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。
Sample Input
3 30
4 40
6 60
3 30
Sample Output
0.33333 0.33333 0.33333 1.00000
【数据规模和约定】
对于100%的数据,1≤n≤5*104, 1≤hi ,vi≤109;
均匀分布着约30%的数据,所有vi均相等。
均匀分布着约50%的数据,满足1≤hi ,vi≤1000。
HINT
题解:
因为精度的问题wa了一天
设定dp[i][0/1] 表示正向和反向的LIS,f[i][0/1] 为其方案数
继承是一个三维偏序,一维排序,二维CDQ,三维树状数组,一次解决
下面是两份不同的代码
#include<bits/stdc++.h>
using namespace std;
#pragma comment(linker, "/STACK:102400000,102400000")
#define ls i<<1
#define rs ls | 1
#define mid ((ll+rr)>>1)
#define pii pair<int,double>
#define MP make_pair
typedef long long LL;
typedef unsigned long long ULL;
const long long INF = 1e18+1LL;
const double pi = acos(-1.0);
const int N = 2e5+, M = 1e3+,inf = 2e9;
struct ss{
int t,x,y;
/*bool operator < (const ss &r) const {
return x == r.x ? y<r.y : x < r.x;
}*/
}a[N],t[N]; bool cmp1(ss s1,ss s2) {
return s1.t < s2.t;
} bool cmp2(ss s1,ss s2) {
if(s1.x == s2.x) {
if(s1.y == s2.y) return s1.t < s2.t;
else return s1.y > s2.y;
}
return s1.x > s2.x;
} vector<double > ans;
int dp[N][],scc = ,tag[N];
double f[N][];
int n;
pair<int,double > C[N],C1[N];
void update(int x,pii now) {
for(int i = x; i ; i -= i&-i) {
if(now.first == )C[i] = MP(,);
else {
if(C[i].first < now.first) {
C[i] = now;
}
else if(C[i].first == now.first) {
C[i].second += now.second;
}
} }
}
pii ask(int x) {
pii ret = MP(,);
for(int i = x; i <= n; i += i&-i) {
if(ret.first < C[i].first) {
ret = C[i];
}
else if(ret.first == C[i].first){
ret.second += C[i].second;
}
}
return ret;
}
void cdq(int ll,int rr,int p) {
if(ll == rr) {
if( f[ll][p] == ) {
dp[ll][p] = ;
f[ll][p] = ;
}
return ;
}
sort(a+ll,a+rr+,cmp1);
cdq(ll,mid,p);
scc++;
sort(a+ll,a+rr+,cmp2);
for(int i = ll; i <= rr; ++i) {
if(a[i].t <= mid) {
update(a[i].y,MP(dp[a[i].t][p],f[a[i].t][p]));
}
else {
pii now = ask(a[i].y);
now.first += ;
if(now.second == ) continue;
if(now.first > dp[a[i].t][p]) {
dp[a[i].t][p] = now.first;
f[a[i].t][p] = now.second;
}
else if(now.first == dp[a[i].t][p]){
f[a[i].t][p] += now.second;
}
}
}
for(int i = ll; i <= rr; ++i) {
if(a[i].t <= mid) update(a[i].y,MP(,));
}
sort(a+ll,a+rr+,cmp1);
cdq(mid+,rr,p);
}
int cnt[N],san[N],cnts;
int main() {
scanf("%d",&n);
int mxxx = ;
for(int i = ; i <= n; ++i) {
scanf("%d%d",&a[i].x,&a[i].y);
san[i] = a[i].y;
mxxx = max(mxxx,a[i].x);
a[i].t = i;
} sort(san+,san+n+);
int SA = unique(san+,san+n+) - san - ;
for(int i = ; i <= n; ++i)
a[i].y = lower_bound(san+,san+SA+, a[i].y) - san; cdq(,n,); sort(a+,a+n+,cmp1);
for(int i =; i <= n; ++i) {
a[i].y = SA - a[i].y + ;
a[i].x = mxxx - a[i].x + ;
}
for(int i = ; i <= n/; ++i) {
swap(a[i].x,a[n - i + ].x);
swap(a[i].y,a[n - i + ].y);
}
cdq(,n,); int ans = ;
for(int i = ; i <= n; ++i) {
ans = max(ans,(int)dp[i][]);
}
printf("%d\n",ans);
double sum = 0.0;
for(int i = ; i <= n; ++i) {
if(dp[i][] == ans) sum += (double)f[i][] * f[n-i+][];
}
for(int i = ; i <= n; ++i) {
if(dp[i][] + dp[n-i+][] - == ans) {
printf("%.5lf",(double)f[i][] * f[n-i+][] / sum);
}
else printf("%.5lf",0.0);
if(i == n) printf("\n");
else printf(" ");
}
return ;
}
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
const int N = 1e5+, M = 1e3+,inf = 2e9; double f[N][];
double dp[N][];
int ch[N];
struct ss {
int t,x,y;
}a[N],t1[N],t2[N];
int cmp(ss s1,ss s2) {
return s1.x > s2.x;
}
double C[N];
double D[N];
double first;
double second;
void update(int x,double firs,double secon) {
for(int i = x; i < N; i += i&(-i)) {
if(C[i] < firs) {
C[i] = firs;
D[i] = secon;
}
else if(C[i] == firs) {
D[i] += secon;
}
}
} void ask(int x) {
first = 0.0,second = 0.0;
for(int i = x; i >= ; i -= i&(-i)) {
if(C[i] > first) {
first = C[i];
second = D[i];
}
else if(C[i] == first) {
second += D[i];
}
}
}
void go(int x) {
for(int i = x; i < N; i += i & (-i)) {
C[i] = ,D[i] = ;
}
}
void CDQ(int ll,int rr,int p) {
if(ll == rr) {
f[ll][p] = max(f[ll][p],1.0);
dp[ll][p] = max(dp[ll][p],1.0);
return ;
}
int mid = (ll+rr)>>;
CDQ(ll,mid,p);
int acnt = , bcnt = , tot = ;
for(int i = ll; i <= mid; ++i) t1[++acnt] = a[i];
for(int i = mid+; i <= rr; ++i) t2[++bcnt] = a[i];
sort(t1+,t1+acnt+,cmp);
sort(t2+,t2+bcnt+,cmp);
int pa = ,pb = ;
while(pb <= bcnt) {
while(pa <= acnt && t1[pa].x >= t2[pb].x) {
update(t1[pa].y,dp[t1[pa].t][p],f[t1[pa].t][p]);
ch[++tot] = t1[pa].y;
pa++;
}
ask(t2[pb].y);
//cout<<first<<" "<<second<<endl;
int id = t2[pb].t;
if(first + > dp[id][p]) {
dp[id][p] = first+;
f[id][p] = second;
}
else if(first + == dp[id][p])
f[id][p] += second;
pb++;
}
for(int i = ; i <= tot; ++i) go(ch[i]);
CDQ(mid+,rr,p);
}
int n,san[N],SA;
int main() {
int mx = -;
scanf("%d",&n);
for(int i = ; i <= n; ++i) {
scanf("%d%d",&a[i].x,&a[i].y);
san[i] = a[i].y;
a[i].t = i;
mx = max(a[i].x,mx);
}
sort(san+,san+n+);
SA = unique(san+,san+n+) - san - ;
for(int i = ; i <= n; ++i)
a[i].y = lower_bound(san+,san+SA+,a[i].y) - san;
for(int i = ; i <= n; ++i) {
a[i].y = SA - a[i].y + ;
}
CDQ(,n,); for(int i = ; i <= n; ++i) {
a[i].y = SA - a[i].y + ;
a[i].x = mx - a[i].x + ;
}
reverse(a+,a+n+);
for(int i = ; i <= n; ++i) {
a[i].t = i;
} CDQ(,n,); int ans = ;
for(int i = ; i <= n; ++i) {
ans = max(ans,(int)dp[i][]);
}
printf("%d\n",ans);
double sum = 0.0;
for(int i = ; i <= n; ++i) {
if(dp[i][] == ans) sum += (double)f[i][] * f[n-i+][];
}
for(int i = ; i <= n; ++i) {
if(dp[i][] + dp[n-i+][] - == ans) {
printf("%.5lf",(double)f[i][] * f[n-i+][] / sum);
}
else printf("%.5lf",0.0);
if(i == n) printf("\n");
else printf(" ");
}
return ;
}
BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治的更多相关文章
- 【BZOJ2244】[SDOI2011]拦截导弹(CDQ分治)
[BZOJ2244][SDOI2011]拦截导弹(CDQ分治) 题面 BZOJ 洛谷 题解 不难发现这就是一个三维偏序+\(LIS\)这样一个\(dp\). 那么第一问很好求,直接\(CDQ\)分治之 ...
- bzoj 2244: [SDOI2011]拦截导弹 cdq分治
2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 237 Solved: ...
- bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)
[题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=2244 [题意] 给定n个二元组,求出最长不上升子序列和各颗导弹被拦截的概率. [思路] ...
- BZOJ - 2244 拦截导弹 (dp,CDQ分治+树状数组优化)
题目链接 dp进阶之CDQ分治优化dp. 前置技能:dp基本功底,CDQ分治,树状数组. 问题等价于求二维最长上升子序列,是一个三维偏序问题(时间也算一维). 设$dp[i]=(l,x)$为以第i枚导 ...
- BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】
题目 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其 ...
- bzoj 2244: [SDOI2011]拦截导弹
#include<cstdio> #include<iostream> #include<algorithm> #define M 100009 using nam ...
- BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)
题意 略- 分析 就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i ...
- bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)
传送门 题解 看了半天完全没发现这东西和CDQ有什么关系…… 先把原序列翻转,求起来方便 然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a ...
- BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]
传送门 题意:三维最长不上升子序列以及每个元素出现在最长不上升子序列的概率 $1A$了好开心 首先需要从左右各求一遍,长度就是$F[0][i]+F[1][i]-1$,次数就是$G[0][i]*G[1] ...
随机推荐
- hdu_2070_Fibbonacci Number
这个题我用long long ,printf("%lld");输出就错误了 我用__int64,printf("%I64d");输出就正确了 这点需要注意. # ...
- SPOJ QTREE Query on a tree V ——动态点分治
[题目分析] QTREE4的弱化版本 建立出分治树,每个节点的堆表示到改点的最近白点距离. 然后分治树上一直向上,取min即可. 正确性显然,不用担心出现在同一子树的情况(不会是最优解),请自行脑补. ...
- 刷题总结——魔术球问题(ssoj最小路径覆盖+网络流)
题目: 题目描述 假设有 n 根柱子,现要按下述规则在这 n 根柱子中依次放入编号为 1,2 ,3,… 的球.(1)每次只能在某根柱子的最上面放球.(2)在同一根柱子中,任何 2 个相邻球的编号之和为 ...
- 【HDOJ5952】Counting Cliques(团,dfs)
题意:给定一张n点m边的图,求大小为S的团的个数 N ≤ 100,M ≤ 1000,2 ≤ S ≤ 10,保证点的度不超过20 思路:dfs 因为每个点可能不止属于一个极大团,所以不能求出极大团然后计 ...
- [C++] 频谱图中 FFT快速傅里叶变换C++实现
在项目中,需要画波形频谱图,因此进行查找,不是很懂相关知识,下列代码主要是针对这篇文章. http://blog.csdn.net/xcgspring/article/details/4749075 ...
- SGU104 二维dp
大致题意: n个东西放在(1.2.3...m)个容器中,先放的必需在后方的左边.a[i][j]表示i号物品放在j容器所得 的价值,求最大价值. 几乎是刚刚开始接触动态规划题,开始我这样想 每个东西一件 ...
- Delphi+MySQL:TADOQuery使用插入中文乱码解决方法
Delphi+MySQL:TADOQuery使用插入中文乱码解决方法 with adoquery dobeginclose;sql.clear;sql.text:=' insert into test ...
- AC日记——租用游艇 洛谷 P1359
题目描述 长江游艇俱乐部在长江上设置了n 个游艇出租站1,2,…,n.游客可在这些游艇出租站租用游艇,并在下游的任何一个游艇出租站归还游艇.游艇出租站i 到游艇出租站j 之间的租金为r(i,j),1& ...
- Oracle 12c在SQL Devolper中添加cdb和pdb连接
Oracle 12c如果按默认流程安装的话会有一个叫orcl的cdb容器和一个叫pdborcld的pdb容器 一.连接名为orcl的cdb容器 连接名:localorcl 用户名:SYS 口令:Ora ...
- Codeforces Round #307 (Div. 2) D. GukiZ and Binary Operations
得到k二进制后,对每一位可取得的方法进行相乘即可,k的二进制形式每一位又分为2种0,1,0时,a数组必定要为一长为n的01串,且串中不出现连续的11,1时与前述情况是相反的. 且0时其方法总数为f(n ...