Description
某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。
Input
第一行包含一个正整数n,表示敌军导弹数量;
下面 行按顺序给出了敌军所有导弹信息:
第i+1行包含2个正整数hi和vi,分别表示第 枚导弹的高度和速度。
Output
输出包含两行。
第一行为一个正整数,表示最多能拦截掉的导弹数量;
第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。
Sample Input
4
3 30
4 40
6 60
3 30
Sample Output
2
0.33333 0.33333 0.33333 1.00000
【数据规模和约定】
对于100%的数据,1≤n≤5*104, 1≤hi ,vi≤109;
均匀分布着约30%的数据,所有vi均相等。
均匀分布着约50%的数据,满足1≤hi ,vi≤1000。
HINT
鸣谢kac提供sj程序!
Source
第一轮day2
隐含着一个三维偏序关系(时间,高度,速度)
所以果断cdq
但是要注意方案数非常,非常,非常大,可以到 225000 !
正确的姿势应该是存对数..但是数据里并没有,所以偷个懒,double骗过去
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
#define MAXN 50010
#define GET (ch>='0'&&ch<='9')
#define lowbit(x) (x&(-x))
using namespace std;
int n;
int sh[MAXN],tph,sv[MAXN],tpv,loc[MAXN];
int sta[MAXN],tp;
void in(int &x)
{
char ch=getchar();x=0;
while (!GET) ch=getchar();
while (GET) x=x*10+ch-'0',ch=getchar();
}
struct Query
{
int id,pos,h,v,f[2];
double g[2];
Query() { id=pos=h=v=0;f[0]=f[1]=0;g[0]=g[1]=0; }
bool operator <(const Query& a)const { return id<a.id; }
}q[MAXN],newq[MAXN];
struct BIT
{
int v;
double sum;
BIT() { v=0;sum=0; }
inline void clear() { v=0;sum=0; }
}tree[MAXN];
inline void add(int x,int v,double delta)
{
for (;x<=tpv;x+=lowbit(x))
if (v>tree[x].v)
{
if (tree[x].v==0) sta[++tp]=x;
tree[x].v=v;tree[x].sum=delta;
}
else
if (v==tree[x].v) tree[x].sum+=delta;
}
inline BIT query(int x)
{
BIT ret;
for (;x;x-=lowbit(x))
if (tree[x].v>ret.v) ret=tree[x];
else
if (tree[x].v==ret.v) ret.sum+=tree[x].sum;
return ret;
}
void solve(int l,int r,int p)
{
if (l==r)
{
if (q[l].f[p]<1) q[l].f[p]=q[l].g[p]=1;
return;
}
int mid=(l+r)>>1,tp1=l,tp2=mid+1;
memcpy(newq+l,q+l,sizeof(Query)*(r-l+1));
for (int i=l;i<=r;i++) (newq[i].pos<=mid?q[tp1++]:q[tp2++])=newq[i];
solve(l,mid,p);tp1=l;
for (int i=mid+1;i<=r;i++)
{
while (tp1<=mid&&q[tp1].id<q[i].id) add(q[tp1].v,q[tp1].f[p],q[tp1].g[p]),tp1++;
BIT tmp=query(q[i].v);
if (!tmp.v) continue;
if (tmp.v+1>q[i].f[p]) q[i].f[p]=tmp.v+1,q[i].g[p]=tmp.sum;
else if (tmp.v+1==q[i].f[p]) q[i].g[p]+=tmp.sum;
}
for (int i=1;i<=tp;i++) tree[sta[i]].clear();tp=0;
solve(mid+1,r,p);
merge(q+l,q+mid+1,q+mid+1,q+r+1,newq+l);memcpy(q+l,newq+l,sizeof(Query)*(r-l+1));
}
inline bool cmp(int a,int b) { return q[a].h==q[b].h?q[a].id<q[b].id:q[a].h<q[b].h; }
int main()
{
in(n);
for (int i=1;i<=n;i++)
in(q[i].h),in(q[i].v),q[i].id=i,
sh[i]=q[i].h,sv[i]=q[i].v,loc[i]=i;
sort(sh+1,sh+n+1);tph=unique(sh+1,sh+n+1)-(sh+1);
sort(sv+1,sv+n+1);tpv=unique(sv+1,sv+n+1)-(sv+1);
for (int i=1;i<=n;i++)
q[i].h=tph-(lower_bound(sh+1,sh+tph+1,q[i].h)-sh)+1,
q[i].v=tpv-(lower_bound(sv+1,sv+tpv+1,q[i].v)-sv)+1;
double Sum=0;int maxn=0;
sort(loc+1,loc+n+1,cmp);
for (int i=1;i<=n;i++) q[loc[i]].pos=i;
solve(1,n,0);
for (int i=1;i<=n;i++)
q[i].pos=n-q[i].pos+1,q[i].id=n-q[i].id+1,
q[i].h=tph-q[i].h+1,q[i].v=tpv-q[i].v+1;
reverse(q+1,q+n+1);solve(1,n,1);reverse(q+1,q+n+1);
for (int i=1;i<=n;i++)
{
int f=q[i].f[0]+q[i].f[1]-1;
double g=q[i].g[0]*q[i].g[1];
if (f>maxn) maxn=f;
if (f==maxn&&q[i].f[1]==1) Sum+=g;
}
printf("%d\n",maxn);
for (int i=1;i<=n;i++)
{
int f=q[i].f[0]+q[i].f[1]-1;
double g=q[i].g[0]*q[i].g[1];
if (f!=maxn) printf("0 ");
else printf("%.6f ",g/Sum);
}
}