bzoj 2244: [SDOI2011]拦截导弹

来源:互联网 发布:完美解码 mac版 编辑:程序博客网 时间:2024/06/06 10:02

题意:

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。

我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。

题解:

容易发现,假如按最长上升子序列的思想,明显是三维偏序。注意这里要先分治左边,然后合并再分治右边。
然后如果想再算方案的话似乎就是四维偏序了,但其实只要求f的时候在树状数组中多存一个量,表方案数,就可以了。
code:

#include<cstdio>#include<cstdlib>#include<cstring>#include<iostream>#include<algorithm>using namespace std;struct node{    int op,x,y,c;}q[50010],tmp[50010];int cnt=0;struct NODE {int h,v,num;}a[50010];int n,h[50010],v[50010],f[4][50010],Q[50010];double g[4][50010];struct trnode{    int max;    double sum;}tr[50010];int lowbit(int x) {return x&-x;}void rechange(int k) {for(int i=k;i<=n;i+=lowbit(i)) tr[i].max=tr[i].sum=0;}void change(int k,int c,double s){    for(int i=k;i<=n;i+=lowbit(i))    {        if(tr[i].max==c) tr[i].sum+=s;        if(tr[i].max<c) tr[i].max=c,tr[i].sum=s;    }}trnode get(int k){    trnode ans;ans.max=0;ans.sum=0;    for(int i=k;i>=1;i-=lowbit(i))    {        if(tr[i].max==ans.max) ans.sum+=tr[i].sum;        if(ans.max<tr[i].max) ans=tr[i];    }    return ans;}bool cmp_h(NODE a,NODE b) {return a.h<b.h;}bool cmp_v(NODE a,NODE b) {return a.v<b.v;}bool cmp1(node a,node b) {return a.x<b.x;}void cdq(int l,int r,int op){    if(l==r) return;    int mid=(l+r)/2;    cdq(l,mid,op);    for(int i=mid+1;i<=r;i++) tmp[i]=q[i];    sort(tmp+mid+1,tmp+r+1,cmp1);    int i=l,j=mid+1,st=0,len=0;    while(i<=mid&&j<=r)    {        if(q[i].x<=tmp[j].x) change(q[i].y,f[op][q[i].c],g[op][q[i].c]),Q[++st]=q[i].y,i++;        else        {            trnode ans=get(tmp[j].y);            if(ans.max<f[op][tmp[j].c]-1) {j++;continue;}            else if(ans.max==f[op][tmp[j].c]-1) g[op][tmp[j].c]+=ans.sum;            else f[op][tmp[j].c]=ans.max+1,g[op][tmp[j].c]=ans.sum;            j++;        }    }    while(j<=r)    {        trnode ans=get(tmp[j].y);        if(ans.max<f[op][tmp[j].c]-1) {j++;continue;}        else if(ans.max==f[op][tmp[j].c]-1) g[op][tmp[j].c]+=ans.sum;        else f[op][tmp[j].c]=ans.max+1,g[op][tmp[j].c]=ans.sum;        j++;    }    for(i=1;i<=st;i++) rechange(Q[i]);    cdq(mid+1,r,op);    i=l;j=mid+1;len=0;    while(i<=mid&&j<=r)    {        if(q[i].x<=q[j].x) tmp[++len]=q[i++];        else tmp[++len]=q[j++];    }    while(i<=mid) tmp[++len]=q[i++];    while(j<=r) tmp[++len]=q[j++];    for(i=1;i<=len;i++) q[l+i-1]=tmp[i];}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++) scanf("%d %d",&a[i].h,&a[i].v),a[i].num=i;    for(int i=1;i<=n;i++) f[1][i]=f[2][i]=1,g[1][i]=g[2][i]=1;    sort(a+1,a+n+1,cmp_h);    int TMP=0;    for(int i=1;i<=n;i++)    {        if(i==1||a[i].h!=a[i-1].h) TMP++;        h[a[i].num]=TMP;    }    sort(a+1,a+n+1,cmp_v);    TMP=0;    for(int i=1;i<=n;i++)    {        if(i==1||a[i].v!=a[i-1].v) TMP++;        v[a[i].num]=TMP;    }    for(int i=1;i<=n;i++) q[n-i+1].x=h[i],q[n-i+1].y=v[i],q[n-i+1].c=i;    cdq(1,n,1);    for(int i=1;i<=n;i++) q[i].x=n-h[i]+1,q[i].y=n-v[i]+1,q[i].c=i;    cdq(1,n,2);    int max=0;double sum=0;    for(int i=1;i<=n;i++)    {        if(max==f[1][i]) sum+=g[1][i];        if(max<f[1][i]) max=f[1][i],sum=g[1][i];    }    printf("%d\n",max);    for(int i=1;i<=n;i++)    {        if(f[1][i]+f[2][i]-1!=max) printf("0.00000 ");        else printf("%.5lf ",g[1][i]*g[2][i]/sum);    }}
原创粉丝点击