[BZOJ2244][SDOI2011]拦截导弹

bzoj
luogu

sol

某一枚导弹被拦截的概率等于这一枚导弹被拦截的方案数,也就是这枚导弹参与构成最长不上升子序列的方案数,除以最长不上升子序列的总方案数。总方案数会爆long long,但是可以用double存(雾)
从前往后做一遍最长不上升子序列,再从后往前做一遍最长不下降子序列,并且求方案数。一枚导弹被拦截的方案数等于前后的方案数的乘积。如果一枚导弹的前后\(dp\)值相加-1不等于LIS,那么这枚导弹就不可能出现在最长不上升子序列里面,因此答案为0。
树套树维护\(dp\)值同时统计方案数。

code

#include<cstdio>
#include<algorithm>
using namespace std;
int gi()
{
	int x=0,w=1;char ch=getchar();
	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
	if (ch=='-') w=0,ch=getchar();
	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
	return w?x:-x;
}
const int N = 5e4+5;
struct Data{
	int f;double g;
	Data operator + (const Data &b) const
		{
			if (f>b.f) return (Data){f,g};
			if (f<b.f) return (Data){b.f,b.g};
			return (Data){f,g+b.g};
		}
}dp[2][N];
struct president_tree{int ls,rs;Data v;}t[N*150];
int n,a[N],b[N],o1[N],o2[N],len1,len2,rt[N],tot,ans;double cnt;
void modify(int &x,int l,int r,int p,Data v)
{
	if (!x) x=++tot;
	t[x].v=t[x].v+v;
	if (l==r) return;int mid=l+r>>1;
	if (p<=mid) modify(t[x].ls,l,mid,p,v);
	else modify(t[x].rs,mid+1,r,p,v);
}
Data query(int x,int l,int r,int ql,int qr)
{
	if (!x||l>=ql&&r<=qr) return t[x].v;
	int mid=l+r>>1;
	if (qr<=mid) return query(t[x].ls,l,mid,ql,qr);
	if (ql>mid) return query(t[x].rs,mid+1,r,ql,qr);
	return query(t[x].ls,l,mid,ql,qr)+query(t[x].rs,mid+1,r,ql,qr);
}
int main()
{
	n=gi();
	for (int i=1;i<=n;++i) o1[++len1]=a[i]=gi(),o2[++len2]=b[i]=gi();
	sort(o1+1,o1+len1+1);len1=unique(o1+1,o1+len1+1)-o1-1;
	sort(o2+1,o2+len2+1);len2=unique(o2+1,o2+len2+1)-o2-1;
	for (int i=1;i<=n;++i)
	{
		a[i]=lower_bound(o1+1,o1+len1+1,a[i])-o1;
		b[i]=lower_bound(o2+1,o2+len2+1,b[i])-o2;
	}
	for (int i=1;i<=n;++i)
	{
		a[i]=len1-a[i]+1;dp[0][i]=(Data){0,1};
		for (int j=a[i];j;j-=j&-j)
			dp[0][i]=dp[0][i]+query(rt[j],1,n,b[i],len2);
		dp[0][i].f++;
		for (int j=a[i];j<=len1;j+=j&-j)
			modify(rt[j],1,n,b[i],dp[0][i]);
	}
	for (int i=1;i<=len1;++i) rt[i]=0;
	for (int i=1;i<=tot;++i) t[i].ls=t[i].rs=0,t[i].v.f=0,t[i].v.g=0;tot=0;
	for (int i=n;i;--i)
	{
		a[i]=len1-a[i]+1;dp[1][i]=(Data){0,1};
		for (int j=a[i];j;j-=j&-j)
			dp[1][i]=dp[1][i]+query(rt[j],1,n,1,b[i]);
		dp[1][i].f++;
		for (int j=a[i];j<=len1;j+=j&-j)
			modify(rt[j],1,n,b[i],dp[1][i]);
	}
	for (int i=1;i<=n;++i) ans=max(ans,dp[0][i].f+dp[1][i].f-1);
	printf("%d\n",ans);
	for (int i=1;i<=n;++i) if (dp[0][i].f==ans) cnt+=dp[0][i].g;
	for (int i=1;i<=n;++i)
		if (ans==dp[0][i].f+dp[1][i].f-1)
			printf("%.6lf ",dp[0][i].g*dp[1][i].g/cnt);
		else printf("0.000000 ");
	puts("");return 0;
}
posted @ 2018-03-14 19:05  租酥雨  阅读(186)  评论(0编辑  收藏  举报