bzoj2244[SDOI2011]拦截导弹

http://www.lydsy.com/JudgeOnline/problem.php?id=2244

第$i$个导弹看成一个三元组$(i,h_i,v_i)$

其实就是最长上升子序列的问题。

我们分别求以第$i$个导弹为结尾的最长上升子序列的长度和个数,以及以第$i$个导弹为开头的最长上升子序列的长度和个数。

下面以求以第$i$个导弹为结尾的最长上升子序列的长度和个数为例。

记以第$i$个导弹结尾的最长上升子序列长度为$f[i]$,则:

$$f[i]=Max\{f[j]|j<i,h[j]\geq h[i],v[j]\geq v[i]\}+1$$

所以第1问就是三维偏序,用CDQ分治解决。

第一维由分治的时候左边小于右边保证;

第二维由排序保证;

第三维由数据结构保证;

看程序应该会比较好理解。

记以第$i$个导弹结尾的最长上升子序列长度为$g[i]$,则:

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

我们可以先按f排序,然后分层DP,还是用CDQ分治。

#include<cstdio>
#include<cstdlib>
#include<iostream>
#include<fstream>
#include<algorithm>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<utility>
#include<set>
#include<bitset>
#include<vector>
#include<functional>
#include<deque>
#include<cctype>
#include<climits>
#include<complex>
//#include<bits/stdc++.h>适用于CF,UOJ,但不适用于poj

using namespace std;

typedef long long LL;
typedef double DB;
typedef pair<int,int> PII;
typedef complex<DB> CP;

#define mmst(a,v) memset(a,v,sizeof(a))
#define mmcy(a,b) memcpy(a,b,sizeof(a))
#define fill(a,l,r,v) fill(a+l,a+r+1,v)
#define re(i,a,b)  for(i=(a);i<=(b);i++)
#define red(i,a,b) for(i=(a);i>=(b);i--)
#define ire(i,x) for(typedef(x.begin()) i=x.begin();i!=x.end();i++)
#define fi first
#define se second
#define m_p(a,b) make_pair(a,b)
#define p_b(a) push_back(a)
#define SF scanf
#define PF printf
#define two(k) (1<<(k))

template<class T>inline T sqr(T x){return x*x;}
template<class T>inline void upmin(T &t,T tmp){if(t>tmp)t=tmp;}
template<class T>inline void upmax(T &t,T tmp){if(t<tmp)t=tmp;}

inline int sgn(DB x){if(abs(x)<1e-9)return 0;return(x>0)?1:-1;}
const DB Pi=acos(-1.0);

int gint()
  {
        int res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }
LL gll()
  {
      LL res=0;bool neg=0;char z;
        for(z=getchar();z!=EOF && z!=‘-‘ && !isdigit(z);z=getchar());
        if(z==EOF)return 0;
        if(z==‘-‘){neg=1;z=getchar();}
        for(;z!=EOF && isdigit(z);res=res*10+z-‘0‘,z=getchar());
        return (neg)?-res:res;
    }

const int maxn=50000;

int n,ny,nz;
struct Ta{int x,y,z,f,flag;DB g;}a[maxn+100];
int bak[maxn+100];

int f1[maxn+100],f2[maxn+100];
DB g1[maxn+100],g2[maxn+100];
int ans;

bool cmpx(Ta a,Ta b){return a.x<b.x;}
bool cmpyx(Ta a,Ta b){return a.y!=b.y?a.y<b.y:a.x<b.x;}//注意y相同时,x小的在前面!!!
bool cmpf(Ta a,Ta b){return a.f<b.f;}

#define lowbit(a) ((a)&(-a))
namespace TREE1
  {
        int tree[maxn+100];
        void update(int a,int v){for(;a<=n;a+=lowbit(a))upmax(tree[a],v);}
        int ask(int a){int res=0;for(;a>=1;a-=lowbit(a))upmax(res,tree[a]);return res;}
        void clear(int a){for(;a<=n;a+=lowbit(a))tree[a]=0;}
  }
void CDQf(int l,int r)
  {
      if(l==r){upmax(a[l].f,1);return;}
      int i,mid=(l+r)/2;
      CDQf(l,mid);
      sort(a+l,a+r+1,cmpyx);
      re(i,l,r)if(a[i].x<=mid)TREE1::update(a[i].z,a[i].f);else upmax(a[i].f,TREE1::ask(a[i].z)+1);
      re(i,l,r)if(a[i].x<=mid)TREE1::clear(a[i].z);
      sort(a+l,a+r+1,cmpx);
      CDQf(mid+1,r);
  }

namespace TREE2
  {
      DB tree[maxn+100];
      void update(int a,DB v){for(;a<=n;a+=lowbit(a))tree[a]+=v;}
      DB ask(int a){DB res=0;for(;a>=1;a-=lowbit(a))res+=tree[a];return res;}
      void clear(int a){for(;a<=n;a+=lowbit(a))tree[a]=0.0;}
  }
void CDQg(int l,int r)
  {
      if(l==r)return;
      int i,mid=(l+r)/2;
      CDQg(l,mid);
      sort(a+l,a+r+1,cmpyx);
      re(i,l,r)
        {
            if(a[i].x<=mid && a[i].flag) TREE2::update(a[i].z,a[i].g);
            if(a[i].x>mid && !a[i].flag) a[i].g+=TREE2::ask(a[i].z);
        }
      re(i,l,r)if(a[i].x<=mid && a[i].flag) TREE2::clear(a[i].z);
      sort(a+l,a+r+1,cmpx);
      CDQg(mid+1,r);
  }

int tmpx[maxn+100];
void solve()
  {
      int i,j,l1,r1,l2,r2;
      re(i,1,n)a[i].f=0,a[i].g=0.0;
      CDQf(1,n);
      sort(a+1,a+n+1,cmpf);
      for(l1=r1=1;r1<n && a[r1+1].f==a[l1].f;r1++);
      re(i,l1,r1)a[i].g=1;
      for(;r1<n;l1=l2,r1=r2)
        {
            for(l2=r2=r1+1;r2<n && a[r2+1].f==a[l2].f;r2++);
            re(i,l1,r1)a[i].flag=1;
            sort(a+l1,a+r2+1,cmpx);
            re(i,l1,r2)tmpx[i]=a[i].x,a[i].x=i;
            CDQg(l1,r2);
            re(i,l1,r2)a[i].x=tmpx[i];
            sort(a+l1,a+r2+1,cmpf);
            re(i,l1,r1)a[i].flag=0;
        }
      sort(a+1,a+n+1,cmpx);
  }

int ans1;
DB ans2;

int main()
  {
      freopen("bzoj2244.in","r",stdin);
      freopen("bzoj2244.out","w",stdout);
        int i;
        n=gint();
        re(i,1,n)a[i].x=i,a[i].y=gint(),a[i].z=gint();

        ny=0;
        re(i,1,n)bak[++ny]=a[i].y;
        sort(bak+1,bak+ny+1);
        ny=unique(bak+1,bak+ny+1)-bak-1;
        re(i,1,n)a[i].y=ny-(lower_bound(bak+1,bak+ny+1,a[i].y)-bak)+1;
        nz=0;
        re(i,1,n)bak[++nz]=a[i].z;
        sort(bak+1,bak+nz+1);
        nz=unique(bak+1,bak+nz+1)-bak-1;
        re(i,1,n)a[i].z=nz-(lower_bound(bak+1,bak+nz+1,a[i].z)-bak)+1;

        solve();
        re(i,1,n)f1[i]=a[i].f,g1[i]=a[i].g;

        re(i,1,n)a[i].x=n-a[i].x+1,a[i].y=ny-a[i].y+1,a[i].z=nz-a[i].z+1;
        re(i,1,n/2)swap(a[i],a[n-i+1]);

        solve();
        re(i,1,n)a[i].x=n-a[i].x+1,a[i].y=ny-a[i].y+1,a[i].z=nz-a[i].z+1;
        re(i,1,n/2)swap(a[i],a[n-i+1]);
        re(i,1,n)f2[i]=a[i].f,g2[i]=a[i].g;

        re(i,1,n)upmax(ans1,f1[i]);
        re(i,1,n)if(f1[i]==ans1)ans2+=g1[i];
        PF("%d\n",ans1);
        re(i,1,n)if(f1[i]+f2[i]-1!=ans1 || sgn(ans2)==0)PF("0.00000 ");else PF("%0.5lf ",g1[i]*g2[i]/ans2);
        return 0;
    }

时间: 2024-12-24 13:45:05

bzoj2244[SDOI2011]拦截导弹的相关文章

bzoj千题计划292:bzoj2244: [SDOI2011]拦截导弹

http://www.lydsy.com/JudgeOnline/problem.php?id=2244 每枚导弹成功拦截的概率 = 包含它的最长上升子序列个数/最长上升子序列总个数 pre_len [i] 表示以i结尾的最长不下降子序列的长度 pre_sum[i] 表示对应长度下的方案数 suf_len[i] 表示以i开头的最长不下降子序列长度 suf_sum[i] 表示对应长度下的方案数 若已有了这4个数组 设最长上升子序列长度=mx 那么 如果pre_len[i]+suf_len[i] -

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]拦截导弹 DP+CDQ分治

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

洛谷 P2487 [SDOI2011]拦截导弹

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

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

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 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]拦截导弹 [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分治/二维树状数组

题目大意:给定一个序列,每个元素是一个二元组,等概率选择一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是一个三维偏序,上