bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2244
【题意】
给定n个二元组,求出最长不上升子序列和各颗导弹被拦截的概率。
【思路】
DP+CDQ分治+BIT
先把序列反转一下,lis求起来方便。
对于第一问,我们要求的是
f[i]=max{ f[j] },j<i,x[j]<x[i],y[j]<y[i]
发现需要满足的条件就是一个三维偏序,可以用CDQ分治求解
不难发现第二问其实就等于:一颗导弹所在的lis数/总的lis数。一个导弹所在的lis必须包含自己,所以我们设g[i]表示以i为结尾的lis总数,则有转移式:
g[i]=sigma{ g[j] }, j<i,x[j]<x[i],y[j]<y[i],f[j]+1=f[i]
依旧可以用CDQ分治求。注意到最后的一个f的关系,这时候只需要统计出之前的最大lis值再与f相比较就可以了(蒟蒻的我一直苦思冥想。。。
相似的可以求出g’f’。都是g f的相反定义,即以i开头的…
奇技淫巧:我们可以在反转一下并对序列取一下反,这样就都可以套用函数辣。貌似离散化之后跑得飞快,一跃直上rk3
【代码】
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define FOR(a,b,c) for(int a=b;a<=c;a++)
using namespace std; const int N = 1e5+; struct Node {
int id,x,y;
bool operator<(const Node& rhs)const {
return x<rhs.x||(x==rhs.x&&y<rhs.y);
}
}q[N],t[N];
bool cmp(const Node& a,const Node& b)
{
return a.id<b.id;
} int f[][N]; double g[][N],ans[N];
int hash[N],tot,n; int read()
{
char c=getchar(); int x=; int f=;
while(!isdigit(c)){if(c=='-')f=-; c=getchar();}
while(isdigit(c)) x=x*+c-'',c=getchar();
return x*f;
} int t_f[N],tag[N],T; double t_g[N];
void add(int x,int f,double g)
{
for(;x<=tot;x+=x&-x) {
if(tag[x]!=T) {tag[x]=T;t_f[x]=;t_g[x]=;}
if(f>t_f[x]){t_f[x]=f;t_g[x]=g;}
else if(f==t_f[x]) t_g[x]+=g;
}
}
void query(int x,int& mx,double& sum)
{
mx=; sum=0.0;
for(;x;x-=x&-x) if(tag[x]==T){
if(t_f[x]>mx) {
mx=t_f[x]; sum=t_g[x];
} else if(t_f[x]==mx)
sum+=t_g[x];
}
} void solve(int l,int r,int ty)
{
if(l==r) {
if(!f[ty][l]){
f[ty][l]=; g[ty][l]=;
}
return ;
}
int mid=(l+r)>>;
int l1=l,l2=mid+,i,j,cnt=;
for(i=l;i<=r;i++) {
if(q[i].id<=mid) t[l1++]=q[i];
else t[l2++]=q[i];
}
memcpy(q+l,t+l,sizeof(Node)*(r-l+));
solve(l,mid,ty);
T++;
sort(q+mid+,q+r+);
for(i=mid+,j=l;i<=r;i++)
{
int id;
for(;j<=mid&&q[j].x<=q[i].x;j++) {
id=q[j].id; cnt++;
add(q[j].y,f[ty][id],g[ty][id]);
}
int mx; double sum;
query(q[i].y,mx,sum);
id=q[i].id;
if(mx>) {
if(mx+>f[ty][id]) {
f[ty][id]=mx+; g[ty][id]=sum;
} else if(mx+==f[ty][id]) {
g[ty][id]+=sum;
}
}
}
solve(mid+,r,ty);
l1=l,l2=mid+; int now=l;
while(l1<=mid||l2<=r) {
if(l2>r||l1<=mid&&q[l1]<q[l2]) t[now++]=q[l1++];
else t[now++]=q[l2++];
}
memcpy(q+l,t+l,sizeof(Node)*(r-l+));
} int main()
{
//freopen("in.in","r",stdin);
//freopen("out.out","w",stdout);
n=read();
int mxx=;
FOR(i,,n)
{
q[i].x=read(),q[i].y=read();
hash[i]=q[i].y;
mxx=max(mxx,q[i].x);
}
sort(hash+,hash+n+);
tot=unique(hash+,hash+n+)-hash-;
FOR(i,,n)
q[i].y=lower_bound(hash+,hash+tot+,q[i].y)-hash;
reverse(q+,q+n+);
FOR(i,,n) q[i].id=i;
solve(,n,); sort(q+,q+n+,cmp);
reverse(q+,q+n+);
FOR(i,,n)
q[i].x=mxx-q[i].x+,q[i].y=tot-q[i].y+,
q[i].id=i;
solve(,n,);
int mx=; double sum=;
FOR(i,,n) {
int tmp=f[][i];
if(tmp>mx) {
mx=tmp; sum=g[][i]*g[][n-i+];
} else if(tmp==mx)
sum+=g[][i]*g[][n-i+];
}
printf("%d\n",mx);
for(int i=n;i;i--) {
if(f[][i]+f[][n-i+]-==mx) {
ans[i]=(g[][i]*g[][n-i+])/sum;
} else ans[i]=;
}
for(int i=n;i>;i--) printf("%.5lf ",ans[i]);
printf("%.5lf",ans[]);
return ;
}
bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)的更多相关文章
- BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治
2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截 ...
- 【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 拦截导弹 (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] ...
随机推荐
- c++ 链接
header.h #ifndef HEADER_H #define HEADER_H unsigned long getFac(unsigned short num); ; #endif // HEA ...
- obj转换成数组
原则上obj是不能转换成数组的.首先array也是obj.只是一个特殊的object. obj一个很关键的点,是拥有成员和方法,撇开方法不说,obj就是一个key-value结构.也就是哈希数组,而j ...
- express中ejs模板引擎
1.在 app.js 中通过以下两个语句设置了 引擎类型 和页面模板的位置: app.set('views', __dirname + '/views'); app.set('view engine' ...
- 如何让WIN32应用程序支持MFC类库
参考链接:http://wenku.baidu.com/view/68fc340c79563c1ec5da714b.html
- Google Play市场考察报告-2
接上文,本次继续考察App. (6)CNBETA win8平板客户端 cnBeta是国内少有的科技类资讯网站,在程序员群体中具有很大影响力.面向程序员的软件应用在APP中一向属于少数,然而程序员群体已 ...
- spring aop环绕通知
[Spring实战]—— 9 AOP环绕通知 假如有这么一个场景,需要统计某个方法执行的时间,如何做呢? 典型的会想到在方法执行前记录时间,方法执行后再次记录,得出运行的时间. 如果采用Sprin ...
- 选择排序的MPI实现
#include "stdafx.h" #include "mpi.h" #include <stdio.h> #include <math. ...
- 网上图书商城项目学习笔记-014购物车模块页面javascrip
一.流程分析 二.代码 1.view层 (1)list.jsp <%@ page language="java" import="java.util.*" ...
- SGU 168
SGU 168,寻找矩阵中右上方,右方,下方最小的元素,采用动态规划解答. #include <iostream> #include <vector> #include < ...
- WPF控件模板和数据模板
来自:http://www.th7.cn/Program/WPF/2011/12/21/51676.shtml ControlTemplate用于描述控件本身. 使用TemplateBinding来绑 ...