1. 程式人生 > >BZOJ2244: [SDOI2011]攔截導彈(CDQ分治,二維LIS,計數)

BZOJ2244: [SDOI2011]攔截導彈(CDQ分治,二維LIS,計數)

Description

某國為了防禦敵國的導彈襲擊,發展出一種導彈攔截系統。但是這種導彈攔截系統有一個缺陷:雖然它的第一發炮彈能夠到達任意的高度、並且能夠攔截任意速度的導彈,但是以後每一發炮彈都不能高於前一發的高度,其攔截的導彈的飛行速度也不能大於前一發。某天,雷達捕捉到敵國的導彈來襲。由於該系統還在試用階段,所以只有一套系統,因此有可能不能攔截所有的導彈。

在不能攔截所有的導彈的情況下,我們當然要選擇使國家損失最小、也就是攔截導彈的數量最多的方案。但是攔截導彈數量的最多的方案有可能有多個,如果有多個最優方案,那麼我們會隨機選取一個作為最終的攔截導彈行動藍圖。

我方間諜已經獲取了所有敵軍導彈的高度和速度,你的任務是計算出在執行上述決策時,每枚導彈被攔截掉的概率。

Input

第一行包含一個正整數n,表示敵軍導彈數量;

下面 行按順序給出了敵軍所有導彈資訊:

i+1行包含2個正整數hivi,分別表示第 枚導彈的高度和速度。

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

解題思路:

讓我想起了前一陣學弟們做的題(手動滑稽)

這道題第一問相當於一個二維LIS。

主要是第二問,我們只需統計有多少最大的答案,和節點在多少方案中,最後相除即可。

最長的只需列舉統計就好了。

而節點在多少方案中可以統計其最長字首LIS和最長字尾LIS,如果相加等於答案+1那麼就合法。

相當於最長字首LIS數量*最長字尾LIS數量。

這個可以用結構體過載運算子實現。

最後中間運算變數可能>1020中間變數要用double,因為double不會爆而是犧牲精度。

程式碼:

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4
#define lll spc<<1 5 #define rrr spc<<1|1 6 const int N=200000; 7 const int M=1000000; 8 struct trnt{ 9 int maxv; 10 double maxt; 11 }tr[M],strnt; 12 struct data{ 13 int t; 14 int h; 15 int tv; 16 int v; 17 }d[N]; 18 int n; 19 int tot; 20 int cnt; 21 double sum; 22 trnt f[N],g[N]; 23 bool cmpb(data a,data b){return a.t<b.t;} 24 bool cmph(data a,data b){return a.h>b.h;} 25 bool cmpv(data a,data b){return a.tv<b.tv;} 26 trnt max(trnt x,trnt y) 27 { 28 trnt ans; 29 if(x.maxv<y.maxv) 30 ans=y; 31 else if(x.maxv>y.maxv) 32 ans=x; 33 else 34 ans=(trnt){x.maxv,x.maxt+y.maxt}; 35 return ans; 36 } 37 void pushup(int spc) 38 { 39 tr[spc]=max(tr[lll],tr[rrr]); 40 return ; 41 } 42 void update(int l,int r,int pos,int spc,int v,double t) 43 { 44 if(l==r) 45 { 46 if(v==-1) 47 tr[spc]=strnt; 48 else{ 49 if(tr[spc].maxv<v) 50 tr[spc]=(trnt){v,t}; 51 else if(tr[spc].maxv==v) 52 tr[spc].maxt+=t; 53 } 54 return ; 55 } 56 int mid=(l+r)>>1; 57 if(pos<=mid) 58 update(l,mid,pos,lll,v,t); 59 else 60 update(mid+1,r,pos,rrr,v,t); 61 pushup(spc); 62 return ; 63 } 64 trnt query(int ll,int rr,int l,int r,int spc) 65 { 66 if(ll>r||l>rr) 67 return strnt; 68 if(ll<=l&&r<=rr) 69 return tr[spc]; 70 int mid=(l+r)>>1; 71 return max(query(ll,rr,l,mid,lll),query(ll,rr,mid+1,r,rrr)); 72 } 73 void CDQ(int l,int r) 74 { 75 if(l==r) 76 return ; 77 int mid=(l+r)>>1; 78 CDQ(l,mid); 79 std::sort(d+l,d+mid+1,cmph); 80 std::sort(d+mid+1,d+r+1,cmph); 81 int j=l; 82 for(int i=mid+1;i<=r;i++) 83 { 84 for(;j<=mid&&d[j].h>=d[i].h;j++) 85 update(1,n,d[j].v,1,f[d[j].t].maxv,f[d[j].t].maxt); 86 trnt tmp=query(d[i].v,n,1,n,1); 87 tmp.maxv++; 88 f[d[i].t]=max(f[d[i].t],tmp); 89 } 90 for(int i=l;i<j;i++) 91 update(1,n,d[i].v,1,-1,0); 92 std::sort(d+mid+1,d+r+1,cmpb); 93 CDQ(mid+1,r); 94 return ; 95 } 96 void Dark_CDQ(int l,int r) 97 { 98 if(l==r) 99 return ; 100 int mid=(l+r)>>1; 101 Dark_CDQ(mid+1,r); 102 std::sort(d+l,d+mid+1,cmph); 103 std::sort(d+mid+1,d+r+1,cmph); 104 int j=r; 105 for(int i=mid;i>=l;i--) 106 { 107 for(;j>=mid+1&&d[j].h<=d[i].h;j--) 108 update(1,n,d[j].v,1,g[d[j].t].maxv,g[d[j].t].maxt); 109 trnt tmp=query(1,d[i].v,1,n,1); 110 tmp.maxv++; 111 g[d[i].t]=max(g[d[i].t],tmp); 112 } 113 for(int i=r;i>j;i--) 114 update(1,n,d[i].v,1,-1,0); 115 std::sort(d+l,d+mid+1,cmpb); 116 Dark_CDQ(l,mid); 117 return ; 118 } 119 int main() 120 { 121 scanf("%d",&n); 122 for(int i=1;i<=n;i++) 123 { 124 scanf("%d%d",&d[i].h,&d[i].tv); 125 d[i].t=i; 126 } 127 std::sort(d+1,d+n+1,cmpv); 128 tot++; 129 d[1].v=1; 130 for(int i=2;i<=n;i++) 131 { 132 if(d[i].tv!=d[i-1].tv) 133 tot++; 134 d[i].v=tot; 135 } 136 std::sort(d+1,d+n+1,cmpb); 137 for(int i=1;i<=n;i++) 138 f[i]=g[i]=(trnt){1,1}; 139 CDQ(1,n); 140 trnt ans=strnt; 141 for(int i=1;i<=n;i++) 142 ans=max(ans,f[i]); 143 printf("%d\n",ans.maxv); 144 for(int i=1;i<=n;i++) 145 if(f[i].maxv==ans.maxv) 146 sum+=(double)(f[i].maxt); 147 std::sort(d+1,d+n+1,cmpb); 148 Dark_CDQ(1,n); 149 std::sort(d+1,d+n+1,cmpb); 150 for(int i=1;i<=n;i++) 151 { 152 if(g[i].maxv+f[i].maxv-1==ans.maxv) 153 printf("%.5lf ",(double)(f[i].maxt)*(double)(g[i].maxt)/sum); 154 else 155 printf("0.00000 "); 156 } 157 puts(""); 158 return 0; 159 }