题意:
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。
题解:
容易发现,假如按最长上升子序列的思想,明显是三维偏序。注意这里要先分治左边,然后合并再分治右边。
然后如果想再算方案的话似乎就是四维偏序了,但其实只要求f的时候在树状数组中多存一个量,表方案数,就可以了。
code:
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
struct node{
int op,x,y,c;
}q[50010],tmp[50010];int cnt=0;
struct NODE {int h,v,num;}a[50010];
int n,h[50010],v[50010],f[4][50010],Q[50010];
double g[4][50010];
struct trnode{
int max;
double sum;
}tr[50010];
int lowbit(int x) {return x&-x;}
void rechange(int k) {for(int i=k;i<=n;i+=lowbit(i)) tr[i].max=tr[i].sum=0;}
void change(int k,int c,double s)
{
for(int i=k;i<=n;i+=lowbit(i))
{
if(tr[i].max==c) tr[i].sum+=s;
if(tr[i].max<c) tr[i].max=c,tr[i].sum=s;
}
}
trnode get(int k)
{
trnode ans;ans.max=0;ans.sum=0;
for(int i=k;i>=1;i-=lowbit(i))
{
if(tr[i].max==ans.max) ans.sum+=tr[i].sum;
if(ans.max<tr[i].max) ans=tr[i];
}
return ans;
}
bool cmp_h(NODE a,NODE b) {return a.h<b.h;}
bool cmp_v(NODE a,NODE b) {return a.v<b.v;}
bool cmp1(node a,node b) {return a.x<b.x;}
void cdq(int l,int r,int op)
{
if(l==r) return;
int mid=(l+r)/2;
cdq(l,mid,op);
for(int i=mid+1;i<=r;i++) tmp[i]=q[i];
sort(tmp+mid+1,tmp+r+1,cmp1);
int i=l,j=mid+1,st=0,len=0;
while(i<=mid&&j<=r)
{
if(q[i].x<=tmp[j].x) change(q[i].y,f[op][q[i].c],g[op][q[i].c]),Q[++st]=q[i].y,i++;
else
{
trnode ans=get(tmp[j].y);
if(ans.max<f[op][tmp[j].c]-1) {j++;continue;}
else if(ans.max==f[op][tmp[j].c]-1) g[op][tmp[j].c]+=ans.sum;
else f[op][tmp[j].c]=ans.max+1,g[op][tmp[j].c]=ans.sum;
j++;
}
}
while(j<=r)
{
trnode ans=get(tmp[j].y);
if(ans.max<f[op][tmp[j].c]-1) {j++;continue;}
else if(ans.max==f[op][tmp[j].c]-1) g[op][tmp[j].c]+=ans.sum;
else f[op][tmp[j].c]=ans.max+1,g[op][tmp[j].c]=ans.sum;
j++;
}
for(i=1;i<=st;i++) rechange(Q[i]);
cdq(mid+1,r,op);
i=l;j=mid+1;len=0;
while(i<=mid&&j<=r)
{
if(q[i].x<=q[j].x) tmp[++len]=q[i++];
else tmp[++len]=q[j++];
}
while(i<=mid) tmp[++len]=q[i++];
while(j<=r) tmp[++len]=q[j++];
for(i=1;i<=len;i++) q[l+i-1]=tmp[i];
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d %d",&a[i].h,&a[i].v),a[i].num=i;
for(int i=1;i<=n;i++) f[1][i]=f[2][i]=1,g[1][i]=g[2][i]=1;
sort(a+1,a+n+1,cmp_h);
int TMP=0;
for(int i=1;i<=n;i++)
{
if(i==1||a[i].h!=a[i-1].h) TMP++;
h[a[i].num]=TMP;
}
sort(a+1,a+n+1,cmp_v);
TMP=0;
for(int i=1;i<=n;i++)
{
if(i==1||a[i].v!=a[i-1].v) TMP++;
v[a[i].num]=TMP;
}
for(int i=1;i<=n;i++) q[n-i+1].x=h[i],q[n-i+1].y=v[i],q[n-i+1].c=i;
cdq(1,n,1);
for(int i=1;i<=n;i++) q[i].x=n-h[i]+1,q[i].y=n-v[i]+1,q[i].c=i;
cdq(1,n,2);
int max=0;double sum=0;
for(int i=1;i<=n;i++)
{
if(max==f[1][i]) sum+=g[1][i];
if(max<f[1][i]) max=f[1][i],sum=g[1][i];
}
printf("%d\n",max);
for(int i=1;i<=n;i++)
{
if(f[1][i]+f[2][i]-1!=max) printf("0.00000 ");
else printf("%.5lf ",g[1][i]*g[2][i]/sum);
}
}