bzoj2244 [SDOI2011]拦截导弹 cdq分治

这个题看起来是二维偏序,但实际上是三维偏序(高度、速度、顺序)

所以就用顺序减掉一维,cdq减掉一维,用数据结构减掉一维,

然后求每个点的概率就等于 经过他的方案数/方案总数

然后首先要知道lis的答案,用cdq分治转移一遍即可出解,但由于要算方案总数,所以需要记录 到一个点 dp值最大时的方案数

但经过他的方案数不只有到一个点的方案数,还有他到终点的方案数,

这时有一个比较显然的结论,对于最长的lis上的每一个点, 存在的充要条件是 前面比他小的点的个数+后面比他大的点的个数=答案-1

对于方案就是用乘法原理,两个方案乘起来即可

比较难写,注意可能会爆int,需要用double


码:

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define zuo o<<1,l,mid
#define you o<<1|1,mid+1,r
#define N 100005
int ql[N<<2],maxx[N<<2],a,b,op,c,n,lin[N],ans,zz;
double cnt,sz[N<<2],d;
struct la
{
	int a,b,c,f,g;
	double sz,sz2;
}D[50005];
void up(int o)
{
	int ll=o<<1,rr=o<<1|1;
if(maxx[ll]==maxx[rr])
{
	sz[o]=sz[ll]+sz[rr];
}else
{
if(maxx[ll]<maxx[rr])swap(ll,rr);
maxx[o]=maxx[ll];
sz[o]=sz[ll];
}
}
void push(int o)
{
	int ll=o<<1,rr=o<<1|1;
if(ql[o])
{
	ql[ll]=ql[rr]=1;
	maxx[ll]=0;
	maxx[rr]=0;	
	sz[ll]=0;
	sz[rr]=0;
	ql[o]=0;
}
}
void gai(int o,int l,int r)
{
	if(a<=l&&r<=b)
	{
		if(op==0)
		{
			if(c==maxx[o])sz[o]+=d;
              if(c>maxx[o])sz[o]=d,maxx[o]=c;
					
		}else
		{
if(c==maxx[o])d+=sz[o];
if(c<maxx[o])c=maxx[o],d=sz[o];			
		}
		return ;
	}
	push(o);
	int mid=(l+r)>>1;
	if(a<=mid)gai(zuo);
	if(b>mid)gai(you);
	up(o);
}
bool cmpa(la A,la B)
{
	return A.a>B.a;
}
bool cmpaa(la A,la B)
{
	return A.a<B.a;
}
bool cmpb(la A,la B)
{
	return A.b<B.b;
}
bool cmpc(la A,la B)
{
	return A.c<B.c;
}
bool cmpcc(la A,la B)
{
	return A.c>B.c;
}
void cdq(int l,int r)
{
	int mid=(l+r)>>1,i;
	if(l==r)return;
	cdq(l,mid);
sort(D+l,D+mid+1,cmpa);
sort(D+mid+1,D+r+1,cmpa);
zz=l;
	for(i=mid+1;i<=r;i++)
	{
		while(D[zz].a>=D[i].a&&zz<=mid)
		{
	a=b=D[zz].b;
    c=D[zz].f;
	d=D[zz].sz;
	op=0;
    gai(1,1,n);zz++;
		}
		a=D[i].b;b=n;
		c=d=0;op=1;
		if(a<=b)gai(1,1,n);
		if(D[i].f==c+1)D[i].sz+=d;
		else if(D[i].f<c+1)
		{
			D[i].f=c+1;
			D[i].sz=d;
		}	
	}
	//清零
	maxx[1]=0;	sz[1]=0;
	ql[1]=1;
	sort(D+mid+1,D+r+1,cmpc);
	cdq(mid+1,r);
}
void cdq2(int l,int r)
{
	int mid=(l+r)>>1,i;
	if(l==r)return;
	cdq2(l,mid);
sort(D+l,D+mid+1,cmpaa);
sort(D+mid+1,D+r+1,cmpaa);
zz=l;
	for(i=mid+1;i<=r;i++)
	{
		while(zz<=mid&&D[zz].a<=D[i].a)
		{
				a=b=D[zz].b;
    c=D[zz].g;d=D[zz].sz;
	op=0;
    gai(1,1,n);zz++;
		}
		a=1;b=D[i].b;
		c=d=0;op=1;
		if(a<=b)gai(1,1,n);
	if(D[i].g==c+1)D[i].sz+=d;
	if(D[i].g<c+1)
	{
		D[i].g=c+1;
		D[i].sz=d;
	}
	}
	//清零
	maxx[1]=0;
	sz[1]=0;
	ql[1]=1;
	sort(D+mid+1,D+r+1,cmpcc);
	cdq2(mid+1,r);
}
int main()
{
	int i;
	scanf("%d",&n);
	for(i=1;i<=n;i++)
	scanf("%d%d",&D[i].a,&D[i].b),D[i].c=i;
	sort(D+1,D+1+n,cmpb);
	for(i=1;i<=n;i++)
	{D[i].f=D[i].g=D[i].sz=1;
		if(D[i].b==D[i-1].b)lin[i]=lin[i-1];
		else lin[i]=i;		
	}
	for(i=1;i<=n;i++)
	D[i].b=lin[i];
	sort(D+1,D+1+n,cmpc);
	cdq(1,n);
	for(i=1;i<=n;i++)
	ans=max(ans,D[i].f),D[i].sz2=D[i].sz,D[i].sz=1;
printf("%d\n",ans);
for(i=1;i<=n;i++)
{
	if(D[i].f==ans)cnt+=D[i].sz2;
}
sort(D+1,D+1+n,cmpcc);
	cdq2(1,n);
sort(D+1,D+1+n,cmpc);
for(i=1;i<=n;i++)
{
if(D[i].g+D[i].f==ans+1)printf("%.5lf ",(D[i].sz*D[i].sz2)/(cnt));
else printf("0.00000 ");
}	
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值