zoukankan      html  css  js  c++  java
  • [BZOJ2244]:拦截导弹(DP+CDQ分治+树状数组)

    题目传送门


    题目描述

    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
    在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
    我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。


    输入格式

    第一行包含一个正整数$n$,表示敌军导弹数量;
    下面行按顺序给出了敌军所有导弹信息:
    第$i+1$行包含$2$个正整数$h_i$和$v_i$,分别表示第$i$枚导弹的高度和速度。


    输出格式

    输出包含两行。
    第一行为一个正整数,表示最多能拦截掉的导弹数量;
    第二行包含$n$个$0$到$1$之间的实数,第$i$个数字表示第$i$枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。


    样例

    样例输入

    4
    3 30
    4 40
    6 60
    3 30

    样例输出

    2
    0.33333 0.33333 0.33333 1.00000


    数据范围与提示

    对于$100%$的数据,$1leqslant nleqslant 5 imes 10^4$,$1leqslant h_i$ ,$v_ileqslant 10^9$;
    均匀分布着约$30%$的数据,所有$v_i$均相等。
    均匀分布着约$50%$的数据,满足$1leqslant h_i,v_ileqslant 1,000$。


    题解

    这道题就是求一个三维的最长非上升子序列的长度($LDS$),肯定要用$CDQ$分治啦~

    利用中序遍历的思想来进行$CDQ$分治,先处理左区间,再处理当前节点的值,最后处理右区间。

    设$f_{1_i}$表示正序时$LDS$的长度,$g_{1_i}$表示个数,$f_{2_i}$和$g_{2_i}$则是逆序。

    处理跟$CDQ$分治一样。

    下面来讲一下如何统计答案:

      第一问的答案就是$max(f_{1_i})$。

      第二问稍繁琐,考虑只有当$f_{1_i}+f_{2_i}-1=max(f_{1_i})$时(减去重复计算的节点$i$),给节点才能成为$LDS$上的点,总方案数即为$g_{1_i} imes g_{2_i}$,答案即为$frac{g_{1_i} imes g_{2_i}}{sum limits_{i=1}^{n}g_{1_i}(f_{1_i}=max)}$。


    代码时刻

    #include<bits/stdc++.h>
    using namespace std;
    struct rec
    {
    	int d;
    	int h;
    	int v;
    	pair<pair<int,double>,pair<int,double> >dp;
    }e[50001];
    int n;
    int flag[50001],hmax,vmax;
    int trmax[200001];
    int ans;
    double sum;
    pair<int,double> tr[200000];//树状数组
    bool cmpd(rec a,rec b){return a.d<b.d;}
    bool cmph1(rec a,rec b){return a.h>b.h;}
    bool cmph2(rec a,rec b){return a.h<b.h;}
    bool cmpv(rec a,rec b){return a.v<b.v;}
    int lowbit(int x){return x&-x;}
    void mem(int x)//清空
    {
    	for(int i=x;i<=n;i+=lowbit(i))
    		tr[i]=make_pair(0,0.0);
    }
    void add(int x,int l,double r)//插入
    {
    	for(int i=x;i<=n;i+=lowbit(i))
    		if(tr[i].first<l)tr[i]=make_pair(l,r);
    		else if(tr[i].first==l)tr[i].second+=r;
    }
    pair<int,double> ask(int x)//查询
    {
    	pair<int,double> res;
    	for(int i=x;i;i-=lowbit(i))
    		if(tr[i].first>res.first)res=tr[i];
    		else if(tr[i].first==res.first)res.second+=tr[i].second;
    	return res;
    }
    void cdq1(int l,int r)//正序CDQ
    {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	cdq1(l,mid);
    	sort(e+l,e+mid+1,cmph1);
    	sort(e+mid+1,e+r+1,cmph1);
    	int i=mid+1,j=l;
    	for(;i<=r;i++)
    	{
    		while(j<=mid&&e[i].h<=e[j].h){add(vmax-e[j].v,e[j].dp.first.first,e[j].dp.first.second);j++;}
    		pair<int,double> frec=ask(vmax-e[i].v);
    		if(e[i].dp.first.first<=frec.first)
    		{
    			e[i].dp.first.first=frec.first+1;
    			e[i].dp.first.second=frec.second;
    		}
    		else if(e[i].dp.first.first==frec.first+1)e[i].dp.first.second+=frec.second;
    	}j--;
    	for(;j>=l;j--)mem(vmax-e[j].v);
    	sort(e+l,e+r+1,cmpd);
    	cdq1(mid+1,r);
    }
    void cdq2(int l,int r)//逆序CDQ
    {
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	cdq2(mid+1,r);
    	sort(e+l,e+mid+1,cmph2);
    	sort(e+mid+1,e+r+1,cmph2);
    	int i=l,j=mid+1;
    	for(;i<=mid;i++)
    	{
    		while(j<=r&&e[i].h>=e[j].h){add(e[j].v,e[j].dp.second.first,e[j].dp.second.second);j++;}
    		pair<int,double> frec=ask(e[i].v);
    		if(e[i].dp.second.first<=frec.first)
    		{
    			e[i].dp.second.first=frec.first+1;
    			e[i].dp.second.second=frec.second;
    		}
    		else if(e[i].dp.second.first==frec.first+1)e[i].dp.second.second+=frec.second;
    	}j--;
    	for(;j>mid;j--)mem(e[j].v);
    	sort(e+l,e+r+1,cmpd);
    	cdq2(l,mid);
    }
    int main()
    {
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    	{
    		e[i].d=i;
    		scanf("%d%d",&e[i].h,&e[i].v);
    		e[i].dp.first.first=e[i].dp.second.first=1;
    		e[i].dp.first.second=e[i].dp.second.second=1.0;
    	}
    	sort(e+1,e+n+1,cmph2);
    	for(int i=1;i<=n;i++)//预处理h
    	{
    		if(e[i].h!=e[i-1].h)flag[0]++;
    		flag[i]=flag[0];
    	}
    	for(int i=1;i<=n;i++)
    		e[i].h=flag[i];
    	flag[0]=0;
    	sort(e+1,e+n+1,cmpv);
    	for(int i=1;i<=n;i++)//预处理v
    	{
    		if(e[i].v!=e[i-1].v)flag[0]++;
    		flag[i]=flag[0];
    	}
    	for(int i=1;i<=n;i++)
    		e[i].v=flag[i];
    	vmax=e[n].v+1;
    	sort(e+1,e+n+1,cmpd);
    	cdq1(1,n);
    	for(int i=1;i<=n;i++)//第一问
    		ans=max(ans,e[i].dp.first.first);
    	cdq2(1,n);
    	for(int i=1;i<=n;i++)
    		if(e[i].dp.first.first+e[i].dp.second.first==ans+1)
    			sum+=e[i].dp.first.second*e[i].dp.second.second;
    	sum/=(double)ans;
    	printf("%d
    ",ans);
    	for(int i=1;i<=n;i++)//第二问
    	{
    		if(e[i].dp.first.first+e[i].dp.second.first==ans+1)
    			printf("%.7lf ",e[i].dp.first.second*e[i].dp.second.second/sum);
    		else printf("0.0000000 ");
    	}
    	return 0;
    }
    

    rp++

  • 相关阅读:
    MySql 用户 及权限操作
    MAC 重置MySQL root 密码
    在mac系统安装Apache Tomcat的详细步骤[转]
    Maven:mirror和repository 区别
    ES6 入门系列
    转场动画CALayer (Transition)
    OC 异常处理
    Foundation 框架
    Enum枚举
    Invalid App Store Icon. The App Store Icon in the asset catalog in 'xxx.app' can’t be transparent nor contain an alpha channel.
  • 原文地址:https://www.cnblogs.com/wzc521/p/11289918.html
Copyright © 2011-2022 走看看