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的位置在哪?”的问题,精确到毫米.但其真正高科技之处在于,它 ...
随机推荐
- Create the Data Access Layer
https://docs.microsoft.com/en-us/aspnet/web-forms/overview/getting-started/getting-started-with-aspn ...
- 2017.9.17校内noip模拟赛解题报告
预计分数:100+60+60=220 实际分数:100+60+40=200 除了暴力什么都不会的我..... T1 2017.9.17巧克力棒(chocolate) 巧克力棒(chocolate)Ti ...
- MySql免安装版绿化版安装配置,附MySQL服务无法启动解决方案
整理于:https://www.cnblogs.com/cenwei/p/6249856.html 我下载的MySQL版本是:mysql-5.6.15-winx64 一.解压文件 下载好My ...
- Flex XML/XMLList 常用操作
1 XML.XMLList操作 Flex对xml提供了很多强大而灵活的操作.相对于其他语言,flex对xml的格式要求不那么苛刻,只要符合基本格式语法的字符串,flex能非常简单的转换成x ...
- javaScript call与apply学习笔记
call和apply是借用他人的函数实现自己到功能,具体表现在改变this指向,借用他人方法 而不同的地方是call是把实参按照形参的个数传入,而apply传入的是一个数组(argument) 写一个 ...
- 51nod 正整数分组
将一堆正整数分为2组,要求2组的和相差最小. 显然我们可以把所有可能组合成的数求出来. 然后从总和的中间开始往大找,找到了就是其中一个的分组,就可以求出答案了. #include<cstdio& ...
- 51nod 编辑距离 + 滚动数组优化
这道题一开始觉得增加和删除会移动字符串的位置很不好做 两个字符串dp状态一般是第一个前i个和第二个前j个 #include<cstdio> #include<algorithm> ...
- 用Understand阅读 VS2010项目源码
一.查看vs2010项目 打开understand,File-New-Project...-Next-Next [向导第三步,选"Import Visual Sudio project fi ...
- HTTP服务器状态码定义
HTTP服务器状态代码定义 1.1 消息1xx(Informational 1xx) 该类状态代码用于表示临时回应.临时回应由状态行(Status-Line)及可选标题组成, 由空行终止.HTTP/1 ...
- easyui 前端实现分页 复制就能用
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...