2244: [SDOI2011]拦截导弹
Time Limit: 30 Sec Memory Limit: 512 MB Special JudgeDescription
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。
Input
第一行包含一个正整数n,表示敌军导弹数量;
下面 行按顺序给出了敌军所有导弹信息:
第i+1行包含2个正整数hi和vi,分别表示第 枚导弹的高度和速度。
Output
输出包含两行。
第一行为一个正整数,表示最多能拦截掉的导弹数量;
第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。
Sample Input
Sample Output
题解:
我们分析一下这道题,其实他分为两个子任务,
一个是计算最长的三维偏序的不下降子序列,
一个是计算每枚导弹在所有可能的方案中出现了多少次.
首先我们离散一下,方便处理.
接着我们考虑,对于导弹i,他处在的导弹序列首先他自己一定在里面,其次序列一定是前面一段后面一段(废话.....)
这样总的方案数就应该是前面一段的方案数*后面一段的方案数.
那么我们考虑类似最短路计数问题的处理方法,我们处理一个类似的f数组,f[0]表示以i开始/f[1]表示以i结束的最长子序列长度
同时统计一个g数组,g[0]表示以i开始/g[0]表示以i结束的最长子序列方案数,在CDQ转移的时候如果长度相等累加,长度不等就覆盖上去
这两个数组正反两遍CDQ就可以计算得到
这样,按照上面的计算方式,总的方案数就应该是g[0][i]*g[1][i].
那么如果某个导弹处在最长子序列中,一定会有f[0][i]+f[1][i]-1==maxlength(-1是因为要把自己减去,不能算两遍)
设总方案数为sum,那么这枚导弹出现的概率就是g[0][i]*g[1][i]/sum
这样我们统计一下上述数组并计算答案即可.
(我偷了下懒,把序列反转之后数值取了下反,就可以不写两遍CDQ,调用同一个函数就行了233)
代码实现:
1 #include <cstdio> 2 #include <cstring> 3 #include <algorithm> 4 #include <iostream> 5 using namespace std; 6 const int N=50010; 7 int n,toth,totv,st[N],top,f[2][N]; 8 struct node 9 { 10 int h,v,tim; 11 inline void read(){scanf("%d%d",&h,&v);} 12 }m[N]; 13 inline bool mt1(const node &a,const node &b) 14 { 15 if(a.v==b.v&&a.h==b.h)return a.tim<b.tim; 16 return a.h==b.h?a.v<b.v:a.h<b.h; 17 } 18 inline bool mt2(const node &a,const node &b) 19 {return a.tim<b.tim;} 20 int bit[N]; 21 double cnt[N],g[2][N],ans[N]; 22 inline int lowbit(int a){return a&-a;} 23 inline void add(int a,int b,double c) 24 { 25 while(a<=totv) 26 { 27 if(bit[a]<b)bit[a]=b,cnt[a]=c; 28 else if(bit[a]==b)cnt[a]+=c; 29 a+=lowbit(a); 30 } 31 } 32 inline void query(int a,int &b,double &c) 33 { 34 b=0,c=0.0; 35 while(a) 36 { 37 if(bit[a]>b)b=bit[a],c=cnt[a]; 38 else if(bit[a]==b)c+=cnt[a]; 39 a-=lowbit(a); 40 } 41 } 42 inline void clear(int a) 43 { 44 while(a<=totv) 45 { 46 if(!bit[a])return; 47 bit[a]=0,cnt[a]=0.0,a+=lowbit(a); 48 } 49 } 50 inline void CDQ(int l,int r,int o) 51 { 52 if(l==r)return; 53 register int i,mi=l+r>>1; 54 CDQ(l,mi,o); 55 sort(m+l,m+r+1,mt1); 56 int x=0;double u=0.0; 57 for(i=l;i<=r;++i) 58 { 59 if(m[i].tim<=mi) 60 add(m[i].v,f[o][m[i].tim],g[o][m[i].tim]); 61 else 62 { 63 query(m[i].v,x,u); 64 if(x+1>f[o][m[i].tim]) 65 f[o][m[i].tim]=x+1,g[o][m[i].tim]=u; 66 else if(x+1==f[o][m[i].tim]) 67 g[o][m[i].tim]+=u; 68 } 69 } 70 for(i=l;i<=r;++i) 71 if(m[i].tim<=mi)clear(m[i].v); 72 sort(m+l,m+r+1,mt2); 73 CDQ(mi+1,r,o); 74 } 75 inline void intn() 76 { 77 register int i; 78 for(i=1;i<=n;++i)st[i]=m[i].h; 79 sort(st+1,st+n+1),toth=unique(st+1,st+n+1)-st-1; 80 for(i=1;i<=n;++i) 81 m[i].h=lower_bound(st+1,st+toth+1,m[i].h)-st; 82 for(i=1;i<=n;++i)st[i]=m[i].v; 83 sort(st+1,st+n+1),totv=unique(st+1,st+n+1)-st-1; 84 for(i=1;i<=n;++i) 85 m[i].v=lower_bound(st+1,st+totv+1,m[i].v)-st; 86 } 87 int main() 88 { 89 register int i,j;scanf("%d",&n); 90 for(i=n;i;--i)m[i].read(); 91 intn(); 92 for(i=1;i<=n;++i) 93 m[i].tim=i,f[0][i]=f[1][i]=g[0][i]=g[1][i]=1; 94 CDQ(1,n,0); 95 reverse(m+1,m+n+1); 96 for(i=1;i<=n;++i) 97 m[i].tim=i,m[i].h=toth-m[i].h+1,m[i].v=totv-m[i].v+1; 98 CDQ(1,n,1); 99 int maxn=0;double sum=0; 100 for(i=1;i<=n;++i) 101 { 102 if(maxn<f[0][i])maxn=f[0][i],sum=g[0][i]; 103 else if(f[0][i]==maxn)sum+=g[0][i]; 104 } 105 printf("%d ",maxn); 106 for(i=1;i<=n;++i) 107 { 108 if(f[0][n-i+1]+f[1][i]-1==maxn) 109 ans[i]=g[0][n-i+1]*g[1][i]/sum; 110 else ans[i]=0.0; 111 } 112 for(i=1;i<n;++i)printf("%.5lf ",ans[i]); 113 printf("%.5lf",ans[n]); 114 }