拦截导弹
【问题描述】
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:
虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都
不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导
弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最
多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机
选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚
导弹被拦截掉的概率。
【输入格式】
第一行包含一个正整数,表示敌军导弹数量;
下面行按顺序给出了敌军所有导弹信息:
第行包含个正整数和,分别表示第枚导弹的高度和速度。
【输出格式】
输出包含两行。
第一行为一个正整数,表示最多能拦截掉的导弹数量;
第二行包含个0 到1 之间的实数,第个数字表示第枚导弹被拦截掉的概率(你可以保留任
意多位有效数字)。
【样例输入】
4
3 30
4 40
6 60
3 30
【样例输出】
2
0.33333 0.33333 0.33333 1.00000
【数据规模和约定】
n<=50000
1<=h,v<=10^9
线段树套线段树
设f[i]为打到这一颗导弹的最长长度
按导弹的顺序扫描,f[i]的取值则为线段树套线段树中满足条件的最大值+1
这样便可以求出来最大值
求出f数组之后,把导弹按f[i]为第一关键字,i为第二关键字排序
用pro[i]表示取了该值之后右边的方案数有多少
按f的取值分阶段扫描,每扫描到一个i,将上一阶段所有大于i的导弹的方案数插入线段树
本阶段扫描完成,将上阶段的导弹全部删除,我采取了插入负数的方式
再用ble[i]表示取了该值左边的方案数有多少种,求的方法类似其pro的方法
每个导弹被打过的概率为(pre[i]*ble[i]/总方案数)
这里对精度要求并不高,而且方案数可能会爆int64,所以采用了extended来存储pre和ble
这个h和v的取值为[1,10^9],我本认为(log(10^9))^2跟(log(10^5))^2差的不是很多,虽然确实差的不算多900跟256的差别……
但线段树不离散化会超时还要爆内存,所以加入离散化
写了9个k
program missile; var w,o,s,e,ans,all,tot,n,i,j,k:longint; sa:extended; quick,new:array [0..100001] of longint; ble,pro:array [0..50001] of extended; dl,v,h,f:array [0..50001] of longint; left,right,root:array [0..1000001] of longint; lef,rig,point:array [0..10000001] of longint; sum:array [0..10000001] of extended; procedure swap (var a,b:longint);inline; var i:longint; begin i:=a; a:=b; b:=i; end; procedure insert1(vi,p,l,r,now:longint;o:extended); var mid:longint; begin sum[now]:=sum[now]+o; if point[now]<p then point[now]:=p; if l=r then exit; mid:=(l+r) div 2; if vi<=mid then begin if lef[now]=0 then begin inc(all); lef[now]:=all; end; insert1(vi,p,l,mid,lef[now],o); end else begin if rig[now]=0 then begin inc(all); rig[now]:=all; end; insert1(vi,p,mid+1,r,rig[now],o); end; end; procedure insert (hi,vi,p,l,r,now:longint;o:extended); var mid:longint; begin if root[now]=0 then begin inc(all); root[now]:=all; end; insert1(vi,p,1,w+1,root[now],o); if l=r then exit; mid:=(l+r) div 2; if hi<=mid then begin if left[now]=0 then begin inc(tot); left[now]:=tot; end; insert(hi,vi,p,l,mid,left[now],o); end else begin if right[now]=0 then begin inc(tot); right[now]:=tot; end; insert(hi,vi,p,mid+1,r,right[now],o); end; end; function find1 (vi,l,r,now:longint):longint; var ans,k,mid:longint; begin if vi=l then exit(point[now]); mid:=(l+r) div 2; if vi>mid then if rig[now]=0 then exit(0) else exit(find1(vi,mid+1,r,rig[now])) else begin ans:=0; if lef[now]=0 then k:=0 else k:=find1(vi,l,mid,lef[now]); if ans<k then ans:=k; if rig[now]=0 then k:=0 else k:=find1(mid+1,mid+1,r,rig[now]); if k>ans then ans:=k; exit(ans); end; end; function find(hi,vi,l,r,now:longint):longint; var ans,k,mid:longint; begin if hi=l then if root[now]=0 then exit(0) else exit(find1(vi,1,w+1,root[now])); mid:=(l+r) div 2; if hi>mid then if right[now]=0 then exit(0) else exit(find(hi,vi,mid+1,r,right[now])) else begin ans:=0; if left[now]=0 then k:=0 else k:=find(hi,vi,l,mid,left[now]); if k>ans then ans:=k; if right[now]=0 then k:=0 else k:=find(mid+1,vi,mid+1,r,right[now]); if k>ans then ans:=k; exit(ans); end; end; function solve1 (vi,l,r,now:longint):extended; var mid:longint; ans:extended; begin if vi=r then exit(sum[now]); mid:=(l+r) div 2; if vi<=mid then if lef[now]=0 then exit(0) else exit(solve1(vi,l,mid,lef[now])) else begin ans:=0; if lef[now]<>0 then ans:=ans+solve1(mid,l,mid,lef[now]); if rig[now]<>0 then ans:=ans+solve1(vi,mid+1,r,rig[now]); exit(ans); end; end; function solve (hi,vi,l,r,now:longint):extended; var mid:longint; ans:extended; begin if r=hi then if root[now]=0 then exit(0) else exit(solve1(vi,1,w+1,root[now])); mid:=(l+r) div 2; if hi<=mid then if left[now]=0 then exit(0) else exit(solve(hi,vi,l,mid,left[now])) else begin ans:=0; if left[now]<>0 then ans:=ans+solve(mid,vi,l,mid,left[now]); if right[now]<>0 then ans:=ans+solve(hi,vi,mid+1,r,right[now]); exit(ans); end; end; function doit1 (vi,l,r,now:longint):extended; var mid:longint; ans:extended; begin if l=vi then exit(sum[now]); mid:=(l+r) div 2; if vi>mid then if rig[now]=0 then exit(0) else exit(doit1(vi,mid+1,r,rig[now])) else begin ans:=0; if lef[now]<>0 then ans:=ans+doit1(vi,l,mid,lef[now]); if rig[now]<>0 then ans:=ans+doit1(mid+1,mid+1,r,rig[now]); exit(ans); end; end; function doit (hi,vi,l,r,now:longint):extended; var mid:longint; ans:extended; begin if l=hi then if root[now]=0 then exit(0) else exit(doit1(vi,1,w+1,root[now])); mid:=(l+r) div 2; if hi>mid then if right[now]=0 then exit(0) else exit(doit(hi,vi,mid+1,r,right[now])) else begin ans:=0; if left[now]<>0 then ans:=ans+doit(hi,vi,l,mid,left[now]); if right[now]<>0 then ans:=ans+doit(mid+1,vi,mid+1,r,right[now]); exit(ans); end; end; procedure qsort (s,e:longint); var i,j,k:longint; begin if s>=e then exit; i:=s; j:=e; k:=dl[(s+e) div 2]; while i<=j do begin while (f[dl[i]]<f[k])or((f[dl[i]]=f[k])and(dl[i]<k)) do inc(i); while (f[dl[j]]>f[k])or((f[dl[j]]=f[k])and(dl[j]>k)) do dec(j); if i>j then break; swap(dl[i],dl[j]); inc(i); dec(j); end; qsort(s,j); qsort(i,e); end; procedure qsort1 (s,e:longint); var i,j,k:longint; begin if s>=e then exit; i:=s; j:=e; k:=quick[(s+e) div 2]; while i<=j do begin while quick[i]<k do inc(i); while quick[j]>k do dec(j); if i>j then break; swap(quick[i],quick[j]); inc(i); dec(j); end; qsort1(s,j); qsort1(i,e); end; function convert (now:longint):longint;inline; var s,e,mid:longint; begin s:=1; e:=w; while s<>e do begin mid:=(s+e) div 2; if new[mid]=now then exit(mid) else if new[mid]>now then e:=mid-1 else s:=mid+1; end; exit(s); end; begin assign(input,'missile.in'); reset(input); assign(output,'missile.out'); rewrite(output); read(n); for i:=1 to n do begin read(h[i],v[i]); quick[2*i-1]:=h[i]; quick[2*i]:=v[i]; end; qsort1(1,2*n); w:=0; i:=1; while i<=2*n do begin k:=i; while quick[i]=quick[k] do inc(i); inc(w); new[w]:=quick[k]; end; for i:=1 to n do begin h[i]:=convert(h[i]); v[i]:=convert(v[i]); end; ans:=1; for i:=1 to n do begin f[i]:=find(h[i],v[i],1,w+1,0)+1; insert(h[i],v[i],f[i],1,w+1,0,0); if f[i]>ans then ans:=f[i]; dl[i]:=i; end; writeln(ans); tot:=0; all:=0; fillchar(left,sizeof(left),0); fillchar(right,sizeof(right),0); fillchar(lef,sizeof(lef),0); fillchar(rig,sizeof(rig),0); fillchar(root,sizeof(root),0); qsort(1,n); h[n+1]:=1; v[n+1]:=1; f[n+1]:=ans+1; pro[n+1]:=1; h[0]:=w+1; v[0]:=w+1; f[0]:=0; dl[n+1]:=n+1; s:=n+1; e:=n+1; i:=n; while i>=0 do begin k:=i; j:=e; while (i>=0)and(f[dl[i]]=f[dl[k]]) do begin while (j>=s)and(dl[j]>dl[i]) do begin insert(h[dl[j]],v[dl[j]],-1,1,w+1,0,pro[dl[j]]); dec(j); end; pro[dl[i]]:=solve(h[dl[i]],v[dl[i]],1,w+1,0); dec(i); end; for o:=j+1 to e do insert(h[dl[o]],v[dl[o]],-1,1,w+1,0,-pro[dl[o]]); e:=s-1; s:=i+1; end; tot:=0; all:=0; fillchar(left,sizeof(left),0); fillchar(right,sizeof(right),0); fillchar(lef,sizeof(lef),0); fillchar(rig,sizeof(rig),0); fillchar(root,sizeof(root),0); fillchar(sum,sizeof(sum),0); s:=0; e:=0; ble[0]:=1; i:=1; while i<=n+1 do begin k:=i; j:=s; while (i<=n+1)and(f[dl[i]]=f[dl[k]]) do begin while (j<=e)and(dl[j]<dl[i]) do begin if pro[dl[j]]>0.1 then insert(h[dl[j]],v[dl[j]],-1,1,w+1,0,ble[dl[j]]); inc(j); end; if pro[dl[i]]>0.1 then ble[dl[i]]:=doit(h[dl[i]],v[dl[i]],1,w+1,0); inc(i); end; for o:=s to j-1 do if pro[dl[o]]>0.1 then insert(h[dl[o]],v[dl[o]],-1,1,w+1,0,-ble[dl[o]]); s:=e+1; e:=i-1; end; for i:=1 to n do write(abs(pro[i]*ble[i]/pro[0]):0:5,' '); writeln; close(input); close(output); end.