BZOJ2244: [SDOI2011]拦截导弹(CDQ分治,二维LIS,计数)
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
解题思路:
让我想起了前一阵学弟们做的题(手动滑稽)
这道题第一问相当于一个二维LIS。
主要是第二问,我们只需统计有多少最大的答案,和节点在多少方案中,最后相除即可。
最长的只需枚举统计就好了。
而节点在多少方案中可以统计其最长前缀LIS和最长后缀LIS,如果相加等于答案+1那么就合法。
相当于最长前缀LIS数量*最长后缀LIS数量。
这个可以用结构体重载运算符实现。
最后中间运算变量可能>1020中间变量要用double,因为double不会爆而是牺牲精度。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lll spc<<1
#define rrr spc<<1|1
const int N=;
const int M=;
struct trnt{
int maxv;
double maxt;
}tr[M],strnt;
struct data{
int t;
int h;
int tv;
int v;
}d[N];
int n;
int tot;
int cnt;
double sum;
trnt f[N],g[N];
bool cmpb(data a,data b){return a.t<b.t;}
bool cmph(data a,data b){return a.h>b.h;}
bool cmpv(data a,data b){return a.tv<b.tv;}
trnt max(trnt x,trnt y)
{
trnt ans;
if(x.maxv<y.maxv)
ans=y;
else if(x.maxv>y.maxv)
ans=x;
else
ans=(trnt){x.maxv,x.maxt+y.maxt};
return ans;
}
void pushup(int spc)
{
tr[spc]=max(tr[lll],tr[rrr]);
return ;
}
void update(int l,int r,int pos,int spc,int v,double t)
{
if(l==r)
{
if(v==-)
tr[spc]=strnt;
else{
if(tr[spc].maxv<v)
tr[spc]=(trnt){v,t};
else if(tr[spc].maxv==v)
tr[spc].maxt+=t;
}
return ;
}
int mid=(l+r)>>;
if(pos<=mid)
update(l,mid,pos,lll,v,t);
else
update(mid+,r,pos,rrr,v,t);
pushup(spc);
return ;
}
trnt query(int ll,int rr,int l,int r,int spc)
{
if(ll>r||l>rr)
return strnt;
if(ll<=l&&r<=rr)
return tr[spc];
int mid=(l+r)>>;
return max(query(ll,rr,l,mid,lll),query(ll,rr,mid+,r,rrr));
}
void CDQ(int l,int r)
{
if(l==r)
return ;
int mid=(l+r)>>;
CDQ(l,mid);
std::sort(d+l,d+mid+,cmph);
std::sort(d+mid+,d+r+,cmph);
int j=l;
for(int i=mid+;i<=r;i++)
{
for(;j<=mid&&d[j].h>=d[i].h;j++)
update(,n,d[j].v,,f[d[j].t].maxv,f[d[j].t].maxt);
trnt tmp=query(d[i].v,n,,n,);
tmp.maxv++;
f[d[i].t]=max(f[d[i].t],tmp);
}
for(int i=l;i<j;i++)
update(,n,d[i].v,,-,);
std::sort(d+mid+,d+r+,cmpb);
CDQ(mid+,r);
return ;
}
void Dark_CDQ(int l,int r)
{
if(l==r)
return ;
int mid=(l+r)>>;
Dark_CDQ(mid+,r);
std::sort(d+l,d+mid+,cmph);
std::sort(d+mid+,d+r+,cmph);
int j=r;
for(int i=mid;i>=l;i--)
{
for(;j>=mid+&&d[j].h<=d[i].h;j--)
update(,n,d[j].v,,g[d[j].t].maxv,g[d[j].t].maxt);
trnt tmp=query(,d[i].v,,n,);
tmp.maxv++;
g[d[i].t]=max(g[d[i].t],tmp);
}
for(int i=r;i>j;i--)
update(,n,d[i].v,,-,);
std::sort(d+l,d+mid+,cmpb);
Dark_CDQ(l,mid);
return ;
}
int main()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
{
scanf("%d%d",&d[i].h,&d[i].tv);
d[i].t=i;
}
std::sort(d+,d+n+,cmpv);
tot++;
d[].v=;
for(int i=;i<=n;i++)
{
if(d[i].tv!=d[i-].tv)
tot++;
d[i].v=tot;
}
std::sort(d+,d+n+,cmpb);
for(int i=;i<=n;i++)
f[i]=g[i]=(trnt){,};
CDQ(,n);
trnt ans=strnt;
for(int i=;i<=n;i++)
ans=max(ans,f[i]);
printf("%d\n",ans.maxv);
for(int i=;i<=n;i++)
if(f[i].maxv==ans.maxv)
sum+=(double)(f[i].maxt);
std::sort(d+,d+n+,cmpb);
Dark_CDQ(,n);
std::sort(d+,d+n+,cmpb);
for(int i=;i<=n;i++)
{
if(g[i].maxv+f[i].maxv-==ans.maxv)
printf("%.5lf ",(double)(f[i].maxt)*(double)(g[i].maxt)/sum);
else
printf("0.00000 ");
}
puts("");
return ;
}
BZOJ2244: [SDOI2011]拦截导弹(CDQ分治,二维LIS,计数)的更多相关文章
- [BZOJ2244][SDOI2011]拦截导弹 CDQ分治
2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec Memory Limit: 512 MB Special Judge Description 某国为了防御敌国的导弹 ...
- bzoj 2244: [SDOI2011]拦截导弹 cdq分治
2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec Memory Limit: 512 MBSec Special JudgeSubmit: 237 Solved: ...
- BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)
题意 略- 分析 就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]f[i ...
- BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]
传送门 题意:三维最长不上升子序列以及每个元素出现在最长不上升子序列的概率 $1A$了好开心 首先需要从左右各求一遍,长度就是$F[0][i]+F[1][i]-1$,次数就是$G[0][i]*G[1] ...
- BZOJ 2244 [SDOI2011]拦截导弹 ——CDQ分治
三维偏序,直接CDQ硬上. 正反两次CDQ统计结尾的方案数,最后统计即可. #include <cstdio> #include <cstring> #include < ...
- BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】
题目 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其 ...
- bzoj2244[SDOI2011]拦截导弹
http://www.lydsy.com/JudgeOnline/problem.php?id=2244 第$i$个导弹看成一个三元组$(i,h_i,v_i)$ 其实就是最长上升子序列的问题. 我们分 ...
- bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹
http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len ...
- COGS1752 [BOI2007]摩基亚Mokia(CDQ分治 + 二维前缀和 + 线段树)
题目这么说的: 摩尔瓦多的移动电话公司摩基亚(Mokia)设计出了一种新的用户定位系统.和其他的定位系统一样,它能够迅速回答任何形如“用户C的位置在哪?”的问题,精确到毫米.但其真正高科技之处在于,它 ...
随机推荐
- uvalive 6669 hidden tree(好壮压dp)
题目见option=com_onlinejudge&Itemid=8&page=show_problem&problem=4681">here 题意:给一个序列 ...
- Lesson 2 Building your first web page: Part 1
In this ‘hands-on’ module we will be building our first web page in no time. We just need to quickly ...
- bean初始化、注销
关于在spring 容器初始化 bean 和销毁前所做的操作定义方式有三种: 第一种:通过@PostConstruct 和 @PreDestroy 方法 实现初始化和销毁bean之前进行的操作 第二 ...
- 如何搭建Eclipse +Apache Tomcat配置Java开发环境
Linux平台下如何搭建Eclipse +Apache Tomcat配置的Java开发环境 本文出自 "李晨光原创技术博客" 博客,请务必保留此出处http://chenguang ...
- C# MVC js 跨域
js 跨域: 第一种解决方案(服务端解决跨域问题): 跨域是浏览器的一种安全策略,是浏览器自身做的限制,不允许用户访问不同域名或端口或协议的网站数据. 只有域名(主域名[一级域名]和二级域名).端口号 ...
- 关于servlet的web.xml映射
1.原理 <servlet> <!-- servlet的名字,随便起个名,但和下面的servlet名一致 --> <servlet-name>hello</s ...
- linux下安装配置rabbitMQ
1.安装Erlang 由于RabbitMQ依赖Erlang, 所以需要先安装Erlang Erlang的安装方式大概有两种: 1.从Erlang Solution安装(推荐) # 添加erlang s ...
- vim插件之ack
这个插件其实是实现vim内部搜索功能的今天在学习vim搜索的时候,遇到了一个ack.vim的插件,这个插件给我们提供了一个并行于系统命令grep的搜索命令Ack 它的下载地址是 https://git ...
- onvif开发总结
ONVIF开发经验总结 ONVIF开发经验总结............................................................................. ...
- 类数组对象arguments 和 数组对象
arguments并不是一个真正的数组,而是一个“类似数组(array-like)”的对象: 就像下面的这段输出,就是典型的类数组对象: {0:12, 1:23} 一.类数组 VS 数组 相同点: 都 ...