bzoj 2244 [SDOI2011]拦截导弹(DP+CDQ分治+BIT)
【题目链接】
http://www.lydsy.com/JudgeOnline/problem.php?id=2244
【题意】
给定n个二元组,求出最长不上升子序列和各颗导弹被拦截的概率。
【思路】
DP+CDQ分治+BIT
先把序列反转一下,lis求起来方便。
对于第一问,我们要求的是
f[i]=max{ f[j] },j<i,x[j]<x[i],y[j]<y[i]
发现需要满足的条件就是一个三维偏序,可以用CDQ分治求解
不难发现第二问其实就等于:一颗导弹所在的lis数/总的lis数。一个导弹所在的lis必须包含自己,所以我们设g[i]表示以i为结尾的lis总数,则有转移式:
g[i]=sigma{ g[j] }, j<i,x[j]<x[i],y[j]<y[i],f[j]+1=f[i]
依旧可以用CDQ分治求。注意到最后的一个f的关系,这时候只需要统计出之前的最大lis值再与f相比较就可以了(蒟蒻的我一直苦思冥想。。。
相似的可以求出g’f’。都是g f的相反定义,即以i开头的…
奇技淫巧:我们可以在反转一下并对序列取一下反,这样就都可以套用函数辣。貌似离散化之后跑得飞快,一跃直上rk3
【代码】
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #define FOR(a,b,c) for(int a=b;a<=c;a++) 6 using namespace std; 7 8 const int N = 1e5+10; 9 10 struct Node { 11 int id,x,y; 12 bool operator<(const Node& rhs)const { 13 return x<rhs.x||(x==rhs.x&&y<rhs.y); 14 } 15 }q[N],t[N]; 16 bool cmp(const Node& a,const Node& b) 17 { 18 return a.id<b.id; 19 } 20 21 int f[2][N]; double g[2][N],ans[N]; 22 int hash[N],tot,n; 23 24 25 int read() 26 { 27 char c=getchar(); int x=0; int f=1; 28 while(!isdigit(c)){if(c=='-')f=-1; c=getchar();} 29 while(isdigit(c)) x=x*10+c-'0',c=getchar(); 30 return x*f; 31 } 32 33 int t_f[N],tag[N],T; double t_g[N]; 34 void add(int x,int f,double g) 35 { 36 for(;x<=tot;x+=x&-x) { 37 if(tag[x]!=T) {tag[x]=T;t_f[x]=0;t_g[x]=0;} 38 if(f>t_f[x]){t_f[x]=f;t_g[x]=g;} 39 else if(f==t_f[x]) t_g[x]+=g; 40 } 41 } 42 void query(int x,int& mx,double& sum) 43 { 44 mx=0; sum=0.0; 45 for(;x;x-=x&-x) if(tag[x]==T){ 46 if(t_f[x]>mx) { 47 mx=t_f[x]; sum=t_g[x]; 48 } else if(t_f[x]==mx) 49 sum+=t_g[x]; 50 } 51 } 52 53 void solve(int l,int r,int ty) 54 { 55 if(l==r) { 56 if(!f[ty][l]){ 57 f[ty][l]=1; g[ty][l]=1; 58 } 59 return ; 60 } 61 int mid=(l+r)>>1; 62 int l1=l,l2=mid+1,i,j,cnt=0; 63 for(i=l;i<=r;i++) { 64 if(q[i].id<=mid) t[l1++]=q[i]; 65 else t[l2++]=q[i]; 66 } 67 memcpy(q+l,t+l,sizeof(Node)*(r-l+1)); 68 solve(l,mid,ty); 69 T++; 70 sort(q+mid+1,q+r+1); 71 for(i=mid+1,j=l;i<=r;i++) 72 { 73 int id; 74 for(;j<=mid&&q[j].x<=q[i].x;j++) { 75 id=q[j].id; cnt++; 76 add(q[j].y,f[ty][id],g[ty][id]); 77 } 78 int mx; double sum; 79 query(q[i].y,mx,sum); 80 id=q[i].id; 81 if(mx>0) { 82 if(mx+1>f[ty][id]) { 83 f[ty][id]=mx+1; g[ty][id]=sum; 84 } else if(mx+1==f[ty][id]) { 85 g[ty][id]+=sum; 86 } 87 } 88 } 89 solve(mid+1,r,ty); 90 l1=l,l2=mid+1; int now=l; 91 while(l1<=mid||l2<=r) { 92 if(l2>r||l1<=mid&&q[l1]<q[l2]) t[now++]=q[l1++]; 93 else t[now++]=q[l2++]; 94 } 95 memcpy(q+l,t+l,sizeof(Node)*(r-l+1)); 96 } 97 98 int main() 99 { 100 //freopen("in.in","r",stdin); 101 //freopen("out.out","w",stdout); 102 n=read(); 103 int mxx=0; 104 FOR(i,1,n) 105 { 106 q[i].x=read(),q[i].y=read(); 107 hash[i]=q[i].y; 108 mxx=max(mxx,q[i].x); 109 } 110 sort(hash+1,hash+n+1); 111 tot=unique(hash+1,hash+n+1)-hash-1; 112 FOR(i,1,n) 113 q[i].y=lower_bound(hash+1,hash+tot+1,q[i].y)-hash; 114 reverse(q+1,q+n+1); 115 FOR(i,1,n) q[i].id=i; 116 solve(1,n,0); 117 118 sort(q+1,q+n+1,cmp); 119 reverse(q+1,q+n+1); 120 FOR(i,1,n) 121 q[i].x=mxx-q[i].x+1,q[i].y=tot-q[i].y+1, 122 q[i].id=i; 123 solve(1,n,1); 124 int mx=0; double sum=0; 125 FOR(i,1,n) { 126 int tmp=f[0][i]; 127 if(tmp>mx) { 128 mx=tmp; sum=g[0][i]*g[1][n-i+1]; 129 } else if(tmp==mx) 130 sum+=g[0][i]*g[1][n-i+1]; 131 } 132 printf("%d\n",mx); 133 for(int i=n;i;i--) { 134 if(f[0][i]+f[1][n-i+1]-1==mx) { 135 ans[i]=(g[0][i]*g[1][n-i+1])/sum; 136 } else ans[i]=0; 137 } 138 for(int i=n;i>1;i--) printf("%.5lf ",ans[i]); 139 printf("%.5lf",ans[1]); 140 return 0; 141 }
posted on 2016-03-10 16:57 hahalidaxin 阅读(1037) 评论(0) 编辑 收藏 举报