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

border="0" width="330" height="86" src="http://music.163.com/outchain/player?type=2&id=25713022&auto=1&height=66">

**

Description

**

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

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


**

Output

**

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


**

Sample Input

**

4

3 30

4 40

6 60

3 30


**

Sample Output

**

2

0.33333 0.33333 0.33333 1.00000

【数据规模和约定】

对于100%的数据,1≤n≤5*104, 1≤hi ,vi≤109;

均匀分布着约30%的数据,所有vi均相等。

均匀分布着约50%的数据,满足1≤hi ,vi≤1000。


**

HINT

**

鸣谢kac提供sj程序!


**

Source

**

第一轮day2


**

Sotution

**
三维偏序——一维排序 二维cdq分治 三维树状数组 然后再做两遍LIS 通过正反和-1==ans 来判断某个数是不是在最后的答案里

代码能力太弱QAQ

**

Code

**

#include <bits/stdc++.h>
using namespace std;
const int maxn=5e4+10;

struct data{
    int x,y,z,f[2];double g[2];
    data(){x=y=z=f[1]=f[0]=0;g[0]=g[1]=0;}
}d[maxn],t[maxn];
bool operator <(data a,data b){return a.y<b.y||(a.y==b.y&&a.x<b.x);}
inline bool cmp(data x,data y){return x.x<y.x;}
struct Bit{
    int w;double sum;
    Bit(){w=0;sum=0;}
    inline void clear(){w=0;sum=0;}
}qu[maxn];
int sta[maxn],tot,n,haz[maxn],hay[maxn],tpz,tpy;
inline Bit ask(int x)
{
    Bit res;
    while(x)
    {
        if(qu[x].w>res.w)res=qu[x];
        else if(qu[x].w==res.w)res.sum+=qu[x].sum;
        x-=x&-x;
    }
    return res;
}
void update(int x,int w,double s)
{
    while(x<=tpz)
    {
        if(qu[x].w<w)
        {
            if(qu[x].w==0)sta[++tot]=x;
            qu[x].w=w;qu[x].sum=s;
        }
        else if(qu[x].w==w)qu[x].sum+=s;
        x+=x&-x;
    }
}

void solve(int l,int r,int p)
{
    if(l==r){if(d[l].f[p]<1)d[l].f[p]=d[l].g[p]=1;return;}
    int mid=(l+r)>>1,st=l,ed=mid+1;
    for(int i=l;i<=r;i++)
        if(d[i].x<=mid)t[st++]=d[i];
        else t[ed++]=d[i];
    for(int i=l;i<=r;i++)d[i]=t[i];
    solve(l,mid,p);
    sort(d+l,d+mid+1);st=l;
    for(int i=mid+1;i<=r;i++)
    {
        while(st<=mid&&d[i].y>=d[st].y)update(d[st].z,d[st].f[p],d[st].g[p]),st++;
        Bit res=ask(d[i].z);
        if(!res.w)continue;
        if(res.w+1>d[i].f[p])d[i].f[p]=res.w+1,d[i].g[p]=res.sum;
        else if(res.w+1==d[i].f[p])d[i].g[p]+=res.sum;
    }
    for(int i=1;i<=tot;i++)qu[sta[i]].clear();tot=0;
    solve(mid+1,r,p);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)scanf("%d%d",&d[i].y,&d[i].z),d[i].x=i,hay[i]=d[i].y,haz[i]=d[i].z;
    sort(hay+1,hay+1+n);sort(haz+1,haz+1+n);
    tpy=unique(hay+1,hay+1+n)-hay-1;tpz=unique(haz+1,haz+1+n)-haz-1;
    for(int i=1;i<=n;i++)
        d[i].y=tpy-(lower_bound(hay+1,hay+1+tpy,d[i].y)-hay)+1,d[i].z=tpz-(lower_bound(haz+1,haz+1+tpz,d[i].z)-haz)+1;
    sort(d+1,d+1+n);
    solve(1,n,0);
    for(int i=1;i<=n;i++)
        d[i].x=n-d[i].x+1,d[i].y=tpy-d[i].y+1,d[i].z=tpz-d[i].z+1;
    reverse(d+1,d+1+n);sort(d+1,d+1+n);
    solve(1,n,1);
    int ans=0;double Sum;
    sort(d+1,d+1+n,cmp);
    reverse(d+1,d+1+n);
    for(int i=1;i<=n;i++)
        if(ans<d[i].f[0])//寻找最长的LIS
        {
            ans=d[i].f[0];
            Sum=d[i].g[0];
        }
        else if(ans==d[i].f[0])
            Sum+=d[i].g[0];
    printf("%d\n",ans);
    for(int i=1;i<=n;i++)
    {
        int len=d[i].f[0]+d[i].f[1]-1;
        if(len<ans)printf("0.00000 ");
        else printf("%.5lf ",d[i].g[0]*d[i].g[1]/Sum);
    }
    return 0;
}


——看不见光明,只能摸索

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值