bzoj 2244: [SDOI2011]拦截导弹

来源:互联网 发布:网络教育的特征 编辑:程序博客网 时间:2024/06/13 01:33

题意

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

题解

很明显的一个CDQ分治DP。。
f[i]表示以他结尾的最多可以拦截多少个
这个用一个CDQ分治很快就可以算出来了
但是有多少种方案怎么弄呢?
其实我们可以在作CDQ的时候顺便弄出一个东西,就是这个答案优多少种方案
这个在树状数组上面加多一个辅助数组就可以了。。
然后经过他的怎么算呢?
我们可以倒着再做一个,求出后面开始,以他为开头的,其他一样,看做g[i]
如果一个导弹,f[i]+g[i]1=ans,那么说明他是在上面的,用哪个辅助的数组统计答案就可以了

需要注意的地方:
1.在分治的时候,注意id的排序,因为我是分开的,前做左边,然后合并最后右边,所以会出现右边的id不顺序的情况
2.方案数乘积会爆longlong,要用double

CODE:(调试都没有删。。)

#include<cstdio>#include<iostream>#include<cstring>#include<algorithm>using namespace std;typedef long long LL;typedef long double LD;const LL N=50005*2;LL n;struct qq{    LL h,v,id;}s[N],k[N];LD f[N],h[N];LD F[N],H[N];//对应的方案数 bool cmph (qq a,qq b){return a.h<b.h;}bool cmpv (qq a,qq b){return a.v<b.v;}bool cmpi (qq a,qq b){return a.id<b.id;}LD g[N],G[N];LL sta[N],top=0;void LSH(){    LL Last,Cnt;    for (LL u=1;u<=n;u++) k[u]=s[u];    sort(k+1,k+1+n,cmph);    Last=0;Cnt=0;    for (LL u=n;u>=1;u--)    {        if (k[u].h!=Last)        {            Last=k[u].h;            Cnt++;        }        s[k[u].id].h=Cnt;    }    for (LL u=1;u<=n;u++) k[u]=s[u];    sort(k+1,k+1+n,cmpv);    Last=0;Cnt=0;    for (LL u=n;u>=1;u--)    {        if (k[u].v!=Last)        {            Last=k[u].v;            Cnt++;        }        s[k[u].id].v=Cnt;    }}LL lb (LL x){return x&(-x);}LD shen;//个数 LL get (LL x){    LD lalal=0;    while (x>=1)    {        if (g[x]>lalal) lalal=g[x],shen=0;        if (g[x]==lalal)    shen=shen+G[x];        x-=lb(x);    }    return lalal;}void change (LL x,LL y,LD z){    while (x<=n)    {        if (g[x]<y) g[x]=y,G[x]=0;        if (g[x]==y) G[x]+=z;        x+=lb(x);    }}void reset (LL x)//这个位置清空 {    while (x<=n)    {        g[x]=0;G[x]=0;        x+=lb(x);    }}void cdq (LL l,LL r){    if (l==r)   return ;/*  printf("OZY:%lld %lld\n",l,r);    for (LL u=l;u<=r;u++) printf("%lld ",s[u].id);        system("pause");*/    LL mid=(l+r)>>1;    sort(s+l,s+r+1,cmpi);    cdq(l,mid);    sort(s+l,s+1+mid,cmph);    sort(s+1+mid,s+r+1,cmph);    LL now=l;//  memset(g,0,sizeof(g));//  memset(G,0,sizeof(G));    top=0;    for (LL u=mid+1;u<=r;u++)//求解    {        while (now<=mid&&s[now].h<=s[u].h)        {            sta[++top]=s[now].v;            change(s[now].v,f[s[now].id],F[s[now].id]);            now++;        }        shen=0;        LL lalal=get(s[u].v)+1;        if (f[s[u].id]<lalal)   f[s[u].id]=lalal,F[s[u].id]=0;        if (f[s[u].id]==lalal) F[s[u].id]+=shen;    }    for (LL u=1;u<=top;u++) reset(sta[u]);    cdq(mid+1,r);/*  for (LL u=1;u<=n;u++) printf("%lld ",f[u]);    printf("\n");*/    return ;}void cdq1 (LL l,LL r){    if (l==r)   return ;/*  printf("OZY:%lld %lld\n",l,r);    for (LL u=l;u<=r;u++) printf("%lld ",s[u].id);        system("pause");*/    LL mid=(l+r)>>1;    sort(s+l,s+r+1,cmpi);    cdq1(mid+1,r);    sort(s+l,s+1+mid,cmph);sort(s+1+mid,s+r+1,cmph);    LL now=mid+1;//  memset(g,0,sizeof(g));//  memset(G,0,sizeof(G));    top=0;    for (LL u=l;u<=mid;u++)//求解?     {        while (now<=r&&s[now].h<=s[u].h)        {                sta[++top]=s[now].v;            change(s[now].v,h[s[now].id],H[s[now].id]);            now++;        }        shen=0;        LL lalal=get(s[u].v)+1;        if (h[s[u].id]<lalal)  h[s[u].id]=lalal,H[s[u].id]=0;        if (h[s[u].id]==lalal) H[s[u].id]+=shen;    }    for (LL u=1;u<=top;u++) reset(sta[u]);    cdq1(l,mid);    return ;}int main(){    scanf("%lld",&n);    for (LL u=1;u<=n;u++)       {        scanf("%lld%lld",&s[u].h,&s[u].v);          s[u].id=u;        f[u]=1;F[u]=1;H[u]=1;h[u]=1;    }    LSH();    sort(s+1,s+1+n,cmpi);    cdq(1,n);    LD ans=0;    for (LL u=1;u<=n;u++) ans=max(ans,f[u]);/*  for (LL u=1;u<=n;u++)     {        printf("%lld:%lld %lld\n",u,f[u],F[u]);    }    printf("\n");*/    printf("%.0Lf\n",ans);    sort(s+1,s+1+n,cmpi);    LSH();    sort(s+1,s+1+n,cmpi);    cdq1(1,n);    LD tot=0;//一共有多少种方案    for (LL u=1;u<=n;u++)        if (f[u]==ans)            tot=tot+F[u];//  printf("%lld\n",tot);    for (LL u=1;u<=n;u++)    {        if (f[u]+h[u]-1==ans)        {            printf("%.5Lf ",F[u]/tot*H[u]);        }        else printf("0.00000 ");    }/*  printf("\n");    printf("f:");    for (LL u=1;u<=n;u++) printf("%lld ",f[u]);/*  printf("\nF:");    for (LL u=1;u<=n;u++) printf("%lld ",F[u]);*//*  printf("\nh:");    for (LL u=1;u<=n;u++) printf("%lld ",h[u]);/*  printf("\nH:");    for (LL u=1;u<=n;u++) printf("%lld ",H[u]);*/    return 0;}
原创粉丝点击