1. 程式人生 > >bzoj 2244 [SDOI2011]攔截導彈(dp+CDQ+樹狀數組)

bzoj 2244 [SDOI2011]攔截導彈(dp+CDQ+樹狀數組)

query style sum ace open printf main 速度 表示

傳送門

題解

看了半天完全沒發現這東西和CDQ有什麽關系……

先把原序列翻轉,求起來方便

然後把每一個位置表示成$(a,b,c)$其中$a$表示位置,$b$表示高度,$c$表示速度,求有多少個位置$a,b,c$都小於它,這就是一個三維偏序問題,直接CDQ就可以解決了……

然後考慮如何求第二問,就是一個導彈所在的LIS數/總的LIS數,因為一個導彈的LIS必須包含自己,以$g[i]$表示以$i$結尾的LIS總數,不難發現有如下轉移式

$$g[i]=\sum g[j] \{ (i<j,h[i]<h[j],v[i]<v[j],f[j]+1=f[i]\}$$

這個也可以用CDQ來解決,只要統計出之前最大的LIS再和$f$比較就好了(完全沒想出來怎麽會這麽神仙……)

然後再求出以$i$為開頭的LIS長度和方案數,兩個相乘就是他自己的方案數了

代碼好長……調了好久……

  1 //minamoto
  2 #include<bits/stdc++.h>
  3 using namespace std;
  4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
  5
char buf[1<<21],*p1=buf,*p2=buf; 6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 7 inline int read(){ 8 #define num ch-‘0‘ 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getc())) 11 (ch==-)&&(flag=true); 12 for
(res=num;isdigit(ch=getc());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 const int N=50005; 18 struct BIT{ 19 int f;double w; 20 BIT(){f=0,w=0;} 21 BIT(int f,double w):f(f),w(w){} 22 }c[N]; 23 int n,st[N],top=0; 24 inline void add(int x,int f,double w){ 25 for(int i=x;i<=n;i+=i&-i){ 26 if(c[i].f<f){ 27 if(c[i].f==0) st[++top]=i; 28 c[i]=(BIT){f,w}; 29 } 30 else if(c[i].f==f) c[i].w+=w; 31 } 32 } 33 inline BIT query(int x){ 34 BIT res; 35 for(int i=x;i;i-=i&-i){ 36 if(c[i].f>res.f) res=c[i]; 37 else if(c[i].f==res.f) res.w+=c[i].w; 38 } 39 return res; 40 } 41 struct node{ 42 int h,v,id,t; 43 int f[2];double g[2]; 44 }a[N],q[N]; 45 int wh[N],wv[N],id[N],rk[N]; 46 inline bool cmp(int i,int j) 47 {return a[i].h<a[j].h||(a[i].h==a[j].h&&a[i].id<a[j].id);} 48 inline bool cmpid(const node &a,const node &b) 49 {return a.id<b.id;} 50 void solve(int l,int r,int t){ 51 if(l==r){ 52 if(a[l].f[t]<1) a[l].f[t]=a[l].g[t]=1; 53 return; 54 } 55 int mid=(l+r)>>1; 56 memcpy(q+l,a+l,sizeof(node)*(r-l+1)); 57 int q1=l,q2=mid+1; 58 for(int i=l;i<=r;++i){ 59 q[i].t<=mid?a[q1++]=q[i]:a[q2++]=q[i]; 60 } 61 solve(l,mid,t); 62 q1=l; 63 for(int i=mid+1;i<=r;++i){ 64 while(q1<=mid&&a[q1].id<a[i].id) add(a[q1].v,a[q1].f[t],a[q1].g[t]),++q1; 65 BIT res=query(a[i].v); 66 if(res.f==0) continue; 67 if(res.f+1>a[i].f[t]){ 68 a[i].f[t]=res.f+1,a[i].g[t]=res.w; 69 } 70 else if(res.f+1==a[i].f[t]) a[i].g[t]+=res.w; 71 } 72 while(top){c[st[top--]]=(BIT){0,0};} 73 solve(mid+1,r,t); 74 merge(a+l,a+mid+1,a+mid+1,a+r+1,q+l,cmpid); 75 memcpy(a+l,q+l,sizeof(node)*(r-l+1)); 76 } 77 int th=0,tv=0; 78 int main(){ 79 //freopen("testdata.in","r",stdin); 80 n=read(); 81 for(int i=1;i<=n;++i){ 82 wh[i]=a[i].h=read(),wv[i]=a[i].v=read(),a[i].id=i,rk[i]=i; 83 } 84 sort(wh+1,wh+1+n),sort(wv+1,wv+1+n); 85 th=unique(wh+1,wh+1+n)-wh-1,tv=unique(wv+1,wv+1+n)-wv-1; 86 for(int i=1;i<=n;++i){ 87 a[i].h=th-(lower_bound(wh+1,wh+th+1,a[i].h)-wh)+1; 88 a[i].v=tv-(lower_bound(wv+1,wv+tv+1,a[i].v)-wv)+1; 89 } 90 sort(rk+1,rk+1+n,cmp); 91 for(int i=1;i<=n;++i) a[rk[i]].t=i; 92 solve(1,n,0); 93 for(int i=1;i<=n;++i){ 94 a[i].h=th-a[i].h+1; 95 a[i].v=tv-a[i].v+1; 96 a[i].id=n-a[i].id+1; 97 a[i].t=n-a[i].t+1; 98 } 99 reverse(a+1,a+1+n); 100 solve(1,n,1); 101 reverse(a+1,a+1+n); 102 double sum=0;int ans=0; 103 for(int i=1;i<=n;++i){ 104 int len=a[i].f[0]+a[i].f[1]-1; 105 cmax(ans,len); 106 } 107 printf("%d\n",ans); 108 for(int i=1;i<=n;++i){ 109 if(a[i].f[0]==ans) sum+=a[i].g[0]*a[i].g[1]; 110 } 111 for(int i=1;i<=n;++i){ 112 double res=a[i].g[0]*a[i].g[1]; 113 printf("%.5lf ",(a[i].f[0]+a[i].f[1]-1==ans)?(res/sum):0); 114 } 115 return 0; 116 }

bzoj 2244 [SDOI2011]攔截導彈(dp+CDQ+樹狀數組)