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的位置在哪?”的问题,精确到毫米.但其真正高科技之处在于,它 ...
随机推荐
- SQL try catch处理
ALTER PROC usp_AccountTransaction @AccountNum INT, @Amount DECIMAL AS BEGIN BEGIN TRY --Start the Tr ...
- PHP获取随机字符串的两种方法
<?php /** * 随机返回字符串 * @param number 返回字符串长度 * @param string 从哪些字符串中随机返回,已设置默认字符串,可空 * @return str ...
- ES6学习笔记(九)Set和Map数据结构
1.set 基本等于Java的Set集合类型,无序不可重复集,常被用来去重. 基本用法 const s = new Set();//通过Set()构造函数创建 [2, 3, 5, 4, 5, 2, 2 ...
- Linux samba服务器安装调试。
samba 做为主要的windown 和 Linux 通讯的服务器之一. 1. 查看是否安装了smb服务. #rpm -ga|grep samba 或者 #service smb status ...
- BZOJ2137: submultiple(生成函数,二项式定理)
Description 设函数g(N)表示N的约数个数.现在给出一个数M,求出所有M的约数x的g(x)的K次方和. Input 第一行输入N,K.N表示M由前N小的素数组成.接下来N行,第i+1行有一 ...
- Yeslab 华为安全HCIE-第七门-Agile Controlle
课程目录: 华为安全HCIE-第七门-Agile Controller(12篇)\1_aglie_controller产品亮点讲解.avi 华为安全HCIE-第七门-Agile Controlle ...
- nginx 实现跨域
nginx 添加头部跨域. location / { add_header 'Access-Control-Allow-Origin' '*'; //允许的域 add_header 'Access-C ...
- HTML5吃豆豆游戏开发实战(一)使用Canvas绘制游戏主角
近期在学习HTML5.爱因斯坦曾说过,"最好的学习就是自己去经历". 于是.我想在学习HTML5的同一时候.做一款简单的小游戏,这样学习起来也会非常有趣的.我想做的是曾经小时候玩儿 ...
- solr 亿万级数据查询性能測试
废话不多说,我电脑配置 i7四核cpu 8G内存 插入数据文档中有5个字段,当中有两个分词.一个int,一个date 批量插入測试一次10万循环10次总共100万用时85秒 批量插入測试一次10万循环 ...
- [BZOJ3526][Poi2014]Card 线段树
链接 题意:有一些卡牌,正反各有一个数,你可以任意翻转,每次操作会将两张卡牌的位置调换,你需要在每次操作后回答以现在的卡牌顺序能否通过反转形成一个单调不降的序列 题解 线段树上维护 \(f[o][0/ ...