bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)

传送门

题解

看了半天完全没发现这东西和CDQ有什么关系……

先把原序列翻转,求起来方便

然后把每一个位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少个位置$a,b,c$都小于它,这就是一个三维偏序问题,直接CDQ就可以解决了……

然后考虑如何求第二问,就是一个导弹所在的LIS数/总的LIS数,因为一个导弹的LIS必须包含自己,以$g[i]$表示以$i$结尾的LIS总数,不难发现有如下转移式

$$g[i]=\sum g[j] \{ (i<j,h[i]<h[j],v[i]<v[j],f[j]+1=f[i]\}$$

这个也可以用CDQ来解决,只要统计出之前最大的LIS再和$f$比较就好了(完全没想出来怎么会这么神仙……)

然后再求出以$i$为开头的LIS长度和方案数,两个相乘就是他自己的方案数了

代码好长……调了好久……

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5 char buf[1<<21],*p1=buf,*p2=buf;
  6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
  7 inline int read(){
  8     #define num ch-‘0‘
  9     char ch;bool flag=0;int res;
 10     while(!isdigit(ch=getc()))
 11     (ch==‘-‘)&&(flag=true);
 12     for(res=num;isdigit(ch=getc());res=res*10+num);
 13     (flag)&&(res=-res);
 14     #undef num
 15     return res;
 16 }
 17 const int N=50005;
 18 struct BIT{
 19     int f;double w;
 20     BIT(){f=0,w=0;}
 21     BIT(int f,double w):f(f),w(w){}
 22 }c[N];
 23 int n,st[N],top=0;
 24 inline void add(int x,int f,double w){
 25     for(int i=x;i<=n;i+=i&-i){
 26         if(c[i].f<f){
 27             if(c[i].f==0) st[++top]=i;
 28             c[i]=(BIT){f,w};
 29         }
 30         else if(c[i].f==f) c[i].w+=w;
 31     }
 32 }
 33 inline BIT query(int x){
 34     BIT res;
 35     for(int i=x;i;i-=i&-i){
 36         if(c[i].f>res.f) res=c[i];
 37         else if(c[i].f==res.f) res.w+=c[i].w;
 38     }
 39     return res;
 40 }
 41 struct node{
 42     int h,v,id,t;
 43     int f[2];double g[2];
 44 }a[N],q[N];
 45 int wh[N],wv[N],id[N],rk[N];
 46 inline bool cmp(int i,int j)
 47 {return a[i].h<a[j].h||(a[i].h==a[j].h&&a[i].id<a[j].id);}
 48 inline bool cmpid(const node &a,const node &b)
 49 {return a.id<b.id;}
 50 void solve(int l,int r,int t){
 51     if(l==r){
 52         if(a[l].f[t]<1) a[l].f[t]=a[l].g[t]=1;
 53         return;
 54     }
 55     int mid=(l+r)>>1;
 56     memcpy(q+l,a+l,sizeof(node)*(r-l+1));
 57     int q1=l,q2=mid+1;
 58     for(int i=l;i<=r;++i){
 59         q[i].t<=mid?a[q1++]=q[i]:a[q2++]=q[i];
 60     }
 61     solve(l,mid,t);
 62     q1=l;
 63     for(int i=mid+1;i<=r;++i){
 64         while(q1<=mid&&a[q1].id<a[i].id) add(a[q1].v,a[q1].f[t],a[q1].g[t]),++q1;
 65         BIT res=query(a[i].v);
 66         if(res.f==0) continue;
 67         if(res.f+1>a[i].f[t]){
 68             a[i].f[t]=res.f+1,a[i].g[t]=res.w;
 69         }
 70         else if(res.f+1==a[i].f[t]) a[i].g[t]+=res.w;
 71     }
 72     while(top){c[st[top--]]=(BIT){0,0};}
 73     solve(mid+1,r,t);
 74     merge(a+l,a+mid+1,a+mid+1,a+r+1,q+l,cmpid);
 75     memcpy(a+l,q+l,sizeof(node)*(r-l+1));
 76 }
 77 int th=0,tv=0;
 78 int main(){
 79     //freopen("testdata.in","r",stdin);
 80     n=read();
 81     for(int i=1;i<=n;++i){
 82         wh[i]=a[i].h=read(),wv[i]=a[i].v=read(),a[i].id=i,rk[i]=i;
 83     }
 84     sort(wh+1,wh+1+n),sort(wv+1,wv+1+n);
 85     th=unique(wh+1,wh+1+n)-wh-1,tv=unique(wv+1,wv+1+n)-wv-1;
 86     for(int i=1;i<=n;++i){
 87         a[i].h=th-(lower_bound(wh+1,wh+th+1,a[i].h)-wh)+1;
 88         a[i].v=tv-(lower_bound(wv+1,wv+tv+1,a[i].v)-wv)+1;
 89     }
 90     sort(rk+1,rk+1+n,cmp);
 91     for(int i=1;i<=n;++i) a[rk[i]].t=i;
 92     solve(1,n,0);
 93     for(int i=1;i<=n;++i){
 94         a[i].h=th-a[i].h+1;
 95         a[i].v=tv-a[i].v+1;
 96         a[i].id=n-a[i].id+1;
 97         a[i].t=n-a[i].t+1;
 98     }
 99     reverse(a+1,a+1+n);
100     solve(1,n,1);
101     reverse(a+1,a+1+n);
102     double sum=0;int ans=0;
103     for(int i=1;i<=n;++i){
104         int len=a[i].f[0]+a[i].f[1]-1;
105         cmax(ans,len);
106     }
107     printf("%d\n",ans);
108     for(int i=1;i<=n;++i){
109         if(a[i].f[0]==ans) sum+=a[i].g[0]*a[i].g[1];
110     }
111     for(int i=1;i<=n;++i){
112         double res=a[i].g[0]*a[i].g[1];
113         printf("%.5lf ",(a[i].f[0]+a[i].f[1]-1==ans)?(res/sum):0);
114     }
115     return 0;
116 }

原文地址:https://www.cnblogs.com/bztMinamoto/p/9459177.html

时间: 2024-12-14 06:51:29

bzoj 2244 [SDOI2011]拦截导弹(dp+CDQ+树状数组)的相关文章

BZOJ 2244: [SDOI2011]拦截导弹 DP+CDQ分治

2244: [SDOI2011]拦截导弹 Description 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发.某天,雷达捕捉到敌国的导弹来袭.由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹. 在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小.也就是拦截导弹的数量最多的方案.但是

bzoj 2244: [SDOI2011]拦截导弹 cdq分治

2244: [SDOI2011]拦截导弹 Time Limit: 30 Sec  Memory Limit: 512 MBSec  Special JudgeSubmit: 237  Solved: 103[Submit][Status][Discuss] Description 某 国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度.并且能够拦截任意速度的导 弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度

BZOJ 2244 SDOI2011 拦截导弹 CDQ分治/二维树状数组

题目大意:给定一个序列,每个元素是一个二元组,等概率选择一LIS,求LIS长度以及每个元素被选中的概率 第一问CDQ分治裸上 第二问用每个元素所在的LIS个数/总LIS个数就是答案 每个元素所在的LIS自己必选,然后统计前面的方案数和后面的方案数 以前面的方案数为例,令f[x]为以x结尾的LIS长度,那么有DP方程: g[i]=Σg[j] (f[j]+1=f[i],j<i,a[j].x<a[i].x,a[j].y<a[i].y) 将所有元素按f值排序,分层DP,每层DP是一个三维偏序,上

BZOJ 2244: [SDOI2011]拦截导弹 [CDQ分治 树状数组]

传送门 题意:三维最长不上升子序列以及每个元素出现在最长不上升子序列的概率 $1A$了好开心 首先需要从左右各求一遍,长度就是$F[0][i]+F[1][i]-1$,次数就是$G[0][i]*G[1][i]$ 我们可以用一些转换来简化代码 反转之后变成$LIS$,然后再反转并且$x,y$取反还是$LIS$,写一遍就可以啦 然后本题的树状数组需要维护最大值以及最大值的数量,还有一个时间戳 #include <iostream> #include <cstdio> #include &

BZOJ 2244 [SDOI2011]拦截导弹 ——CDQ分治

三维偏序,直接CDQ硬上. 正反两次CDQ统计结尾的方案数,最后统计即可. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; #define F(i,j,k) for (int i=j;i<=k;++i) #define D(i,j,k) for (int i=j;i>=i;--i) #define

bzoj 2244: [SDOI2011]拦截导弹

1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #define M 100009 5 using namespace std; 6 struct data 7 { 8 int x,y,z,f[2]; 9 double sum[2]; 10 }a[M],b[M]; 11 struct ss 12 { 13 int w; 14 double su; 15 }shu[M]; 16 int n,yy

BZOJ 1452: [JSOI2009]Count (二维树状数组)

Description Input Output Sample Input Sample Output 1 2 HINT 二维树状数组的简单应用,c数组的第一维坐标相当于哈希.如果是修改操作,修改前 将当前的值的个数以及祖先都减1, 修改后将个数加1. #include <iostream> #include <cstring> #include <cstdio> #include <cmath> #include <set> #include

【BZOJ】1012: [JSOI2008]最大数maxnumber(树状数组+区间最值)

http://www.lydsy.com/JudgeOnline/problem.php?id=1012 树状数组原来我只懂得sum和add的操作,今天才知道可以有求区间最值的操作,我学习了一下写了个,1a了. 区间最值其实和区间求和差不多,就是将sum数组的含义转移到max,然后通过特定的区间更新max. 在区间求和中,当我们维护max[i]的时候,要找到它前面所有的max[j]来更新,在这里因为是树状数组,所以可以降成一个log级,画图可知,max[i]需要的max只有max[i-2^0],

HDU 2227 Find the nondecreasing subsequences dp思想 + 树状数组

http://acm.hdu.edu.cn/showproblem.php?pid=2227 用dp[i]表示以第i个数为结尾的nondecreasing串有多少个. 那么对于每个a[i] 要去找 <= a[i]的数字那些位置,加上他们的dp值即可. 可以用树状数组维护 #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algori