【SDOI2011】【BZOJ2244】拦截导弹

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

隐含着一个三维偏序关系(时间,高度,速度)
所以果断cdq
但是要注意方案数非常,非常,非常大,可以到 225000 !
正确的姿势应该是存对数..但是数据里并没有,所以偷个懒,double骗过去

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define MAXN 50010
#define GET (ch>='0'&&ch<='9')
#define lowbit(x) (x&(-x))
using namespace std;
int n;
int sh[MAXN],tph,sv[MAXN],tpv,loc[MAXN];
int sta[MAXN],tp;
void in(int &x)
{
    char ch=getchar();x=0;
    while (!GET)    ch=getchar();
    while (GET) x=x*10+ch-'0',ch=getchar();
}
struct Query
{
    int id,pos,h,v,f[2];
    double g[2];
    Query() {   id=pos=h=v=0;f[0]=f[1]=0;g[0]=g[1]=0;   }
    bool operator <(const Query& a)const    {   return id<a.id; }
}q[MAXN],newq[MAXN];
struct BIT
{
    int v;
    double sum;
    BIT()   {   v=0;sum=0;  }
    inline void clear() {   v=0;sum=0;  }
}tree[MAXN];
inline void add(int x,int v,double delta)
{
    for (;x<=tpv;x+=lowbit(x))
        if (v>tree[x].v)
        {
            if (tree[x].v==0)   sta[++tp]=x;
            tree[x].v=v;tree[x].sum=delta;
        }
        else
        if (v==tree[x].v)   tree[x].sum+=delta;
}
inline BIT query(int x)
{
    BIT ret;
    for (;x;x-=lowbit(x))
        if (tree[x].v>ret.v)    ret=tree[x];
        else    
        if (tree[x].v==ret.v)   ret.sum+=tree[x].sum;
    return ret;
}
void solve(int l,int r,int p)
{
    if (l==r)
    {
        if (q[l].f[p]<1)    q[l].f[p]=q[l].g[p]=1;
        return;
    }
    int mid=(l+r)>>1,tp1=l,tp2=mid+1;
    memcpy(newq+l,q+l,sizeof(Query)*(r-l+1));
    for (int i=l;i<=r;i++)  (newq[i].pos<=mid?q[tp1++]:q[tp2++])=newq[i];
    solve(l,mid,p);tp1=l;
    for (int i=mid+1;i<=r;i++)
    {
        while (tp1<=mid&&q[tp1].id<q[i].id) add(q[tp1].v,q[tp1].f[p],q[tp1].g[p]),tp1++;
        BIT tmp=query(q[i].v);
        if (!tmp.v) continue;
        if (tmp.v+1>q[i].f[p])  q[i].f[p]=tmp.v+1,q[i].g[p]=tmp.sum;
        else    if (tmp.v+1==q[i].f[p]) q[i].g[p]+=tmp.sum;
    }
    for (int i=1;i<=tp;i++) tree[sta[i]].clear();tp=0;
    solve(mid+1,r,p);
    merge(q+l,q+mid+1,q+mid+1,q+r+1,newq+l);memcpy(q+l,newq+l,sizeof(Query)*(r-l+1));
}
inline bool cmp(int a,int b)    {   return q[a].h==q[b].h?q[a].id<q[b].id:q[a].h<q[b].h;    }
int main()
{
    in(n);
    for (int i=1;i<=n;i++)
        in(q[i].h),in(q[i].v),q[i].id=i,
        sh[i]=q[i].h,sv[i]=q[i].v,loc[i]=i;
    sort(sh+1,sh+n+1);tph=unique(sh+1,sh+n+1)-(sh+1);
    sort(sv+1,sv+n+1);tpv=unique(sv+1,sv+n+1)-(sv+1);
    for (int i=1;i<=n;i++)
        q[i].h=tph-(lower_bound(sh+1,sh+tph+1,q[i].h)-sh)+1,
        q[i].v=tpv-(lower_bound(sv+1,sv+tpv+1,q[i].v)-sv)+1;
    double Sum=0;int maxn=0;
    sort(loc+1,loc+n+1,cmp);
    for (int i=1;i<=n;i++)  q[loc[i]].pos=i;
    solve(1,n,0);
    for (int i=1;i<=n;i++)
        q[i].pos=n-q[i].pos+1,q[i].id=n-q[i].id+1,
        q[i].h=tph-q[i].h+1,q[i].v=tpv-q[i].v+1;
    reverse(q+1,q+n+1);solve(1,n,1);reverse(q+1,q+n+1);
    for (int i=1;i<=n;i++)
    {
        int f=q[i].f[0]+q[i].f[1]-1;
        double g=q[i].g[0]*q[i].g[1];
        if (f>maxn) maxn=f;
        if (f==maxn&&q[i].f[1]==1)  Sum+=g;
    }
    printf("%d\n",maxn);
    for (int i=1;i<=n;i++)
    {
        int f=q[i].f[0]+q[i].f[1]-1;
        double g=q[i].g[0]*q[i].g[1];
        if (f!=maxn)    printf("0 ");
        else    printf("%.6f ",g/Sum);
    }
}

你可能感兴趣的:(分治)