BZOJ 2244 SDOI2011 拦截导弹 CDQ分治/二维树状数组

32 篇文章 0 订阅
8 篇文章 0 订阅

题目大意:给定一个序列,每个元素是一个二元组,等概率选择一LIS,求LIS长度以及每个元素被选中的概率

第一问CDQ分治裸上

第二问用每个元素所在的LIS个数/总LIS个数就是答案

每个元素所在的LIS自己必选,然后统计前面的方案数和后面的方案数

以前面的方案数为例,令f[x]为以x结尾的LIS长度,那么有DP方程:

g[i]=Σg[j] (f[j]+1=f[i],j<i,a[j].x<a[i].x,a[j].y<a[i].y)

将所有元素按f值排序,分层DP,每层DP是一个三维偏序,上CDQ分治再搞搞就好了

(我偷懒写了二维树状数组QAQ)

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 50500
using namespace std;
typedef double ld;
int n,ans,tot;
int f[M];
ld g[M],h[M],total;
struct abcd{
	int x,y;
}*a[M],*_a[M],mempool[M];
bool Compare(abcd *a1,abcd *a2)
{
	if( a1->x != a2->x )
		return a1->x < a2->x ;
	return a1->y < a2->y ;
}
bool _Compare(int x,int y)
{
	if( f[x] != f[y] )
		return f[x] < f[y] ;
	return x < y ;
}
void Discretization()
{
	static pair<int,int*> b[M];
	int i;
	for(i=1;i<=n;i++)
		b[i]=make_pair(-a[i]->x,&a[i]->x);
	sort(b+1,b+n+1);
	for(tot=0,i=1;i<=n;i++)
	{
		if(i==1||b[i].first!=b[i-1].first)
			++tot;
		*b[i].second=tot;
	}

	for(i=1;i<=n;i++)
		b[i]=make_pair(-a[i]->y,&a[i]->y);
	sort(b+1,b+n+1);
	for(tot=0,i=1;i<=n;i++)
	{
		if(i==1||b[i].first!=b[i-1].first)
			++tot;
		*b[i].second=tot;
	}
}
namespace BIT{
	int c[M],tim[M],T;
	void Initialize()
	{
		++T;
	}
	void Update(int x,int y)
	{
		for(;x<=n;x+=x&-x)
		{
			if(tim[x]!=T)
				tim[x]=T,c[x]=0;
			c[x]=max(c[x],y);
		}
	}
	int Get_Ans(int x)
	{
		int re=0;
		for(;x;x-=x&-x)
			if(tim[x]==T)
				re=max(re,c[x]);
		return re;
	}
}
void CDQ_Divide_And_Conquer(int l,int r)
{
	using namespace BIT;
	int i,j,mid=l+r>>1;
	if(l==r)
	{
		f[mid]++;
		ans=max(ans,f[mid]);
		return ;
	}
	int l1=l,l2=mid+1;
	for(i=l;i<=r;i++)
		if(a[i]-mempool<=mid)
			_a[l1++]=a[i];
		else
			_a[l2++]=a[i];
	memcpy(a+l,_a+l,sizeof(a[0])*(r-l+1));
	CDQ_Divide_And_Conquer(l,mid);
	Initialize();
	for(j=l,i=mid+1;i<=r;i++)
	{
		for(;j<=mid&&a[j]->x<=a[i]->x;j++)
			Update(a[j]->y,f[a[j]-mempool]);
		f[a[i]-mempool]=max(f[a[i]-mempool],Get_Ans(a[i]->y));
	}
	CDQ_Divide_And_Conquer(mid+1,r);
	l1=l;l2=mid+1;
	for(i=l;i<=r;i++)
		if( l2>r || l1<=mid && Compare(a[l1],a[l2]) )
			_a[i]=a[l1++];
		else
			_a[i]=a[l2++];
	memcpy(a+l,_a+l,sizeof(a[0])*(r-l+1));
}
namespace Bidimensional_BIT{
	namespace Hash_Table{
		struct List{
			int x,y;
			ld val;
			List *next;
			List() {}
			List(int _,int __,List *___):
				x(_),y(__),val(0),next(___) {}
		}mempool[12000000],*C=mempool,*head[1031][1301];
		int tim[1031][1301],T;
		void Initialize()
		{
			C=mempool;
			++T;
		}
		ld& Hash(int x,int y)
		{
			int pos1=x%1031,pos2=y%1301;
			List *temp;
			if(tim[pos1][pos2]!=T)
				tim[pos1][pos2]=T,head[pos1][pos2]=0;
			for(temp=head[pos1][pos2];temp;temp=temp->next)
				if(temp->x==x&&temp->y==y)
					return temp->val;
			return (head[pos1][pos2]=new List(x,y,head[pos1][pos2]))->val;
		}
		ld Get_Hash(int x,int y)
		{
			int pos1=x%1031,pos2=y%1301;
			List *temp;
			if(tim[pos1][pos2]!=T)
				tim[pos1][pos2]=T,head[pos1][pos2]=0;
			for(temp=head[pos1][pos2];temp;temp=temp->next)
				if(temp->x==x&&temp->y==y)
					return temp->val;
			return 0;
		}
	}
	using namespace Hash_Table;
	void Update(int x,int y,ld val,int flag)
	{
		int i,j;
		for(i=x;i&&i<=n;i+=flag*(i&-i))
			for(j=y;j&&j<=n;j+=flag*(j&-j))
				Hash(i,j)+=val;
	}
	ld Get_Ans(int x,int y,int flag)
	{
		ld re=0;
		int i,j;
		for(i=x;i&&i<=n;i+=flag*(i&-i))
			for(j=y;j&&j<=n;j+=flag*(j&-j))
				re+=Get_Hash(i,j);
		return re;
	}
}
int main()
{
	//freopen("3756.in","r",stdin);
	//freopen("3756.out","w",stdout);
	int i,j;
	cin>>n;
	for(i=1;i<=n;i++)
	{
		scanf("%d%d",&mempool[i].x,&mempool[i].y);
		a[i]=&mempool[i];
	}
	Discretization();
	sort(a+1,a+n+1,Compare);
	CDQ_Divide_And_Conquer(1,n);
	cout<<ans<<endl;
	static int a[M];
	for(i=1;i<=n;i++)
		a[i]=i;
	sort(a+1,a+n+1,_Compare);
	for(i=1;i<=n&&f[a[i]]==1;i++)
		g[a[i]]=1;
	for(j=1;i<=n;i++)
	{
		if(f[a[i]]!=f[a[i-1]])
		{
			for(;f[a[j]]+1!=f[a[i]];j++);
			Bidimensional_BIT::Initialize();
		}
		for(;a[j]<a[i]&&f[a[j]]==f[a[i]]-1;j++)
			Bidimensional_BIT::Update(mempool[a[j]].x,mempool[a[j]].y,g[a[j]],1);
		g[a[i]]=Bidimensional_BIT::Get_Ans(mempool[a[i]].x,mempool[a[i]].y,-1);
	}
	for(i=n;i&&f[a[i]]==ans;i--)
		h[a[i]]=1;
	for(j=n;i;i--)
	{
		if(f[a[i]]!=f[a[i+1]])
		{
			for(;f[a[j]]-1!=f[a[i]];j--);
			Bidimensional_BIT::Initialize();
		}
		for(;a[j]>a[i]&&f[a[j]]==f[a[i]]+1;j--)
			Bidimensional_BIT::Update(mempool[a[j]].x,mempool[a[j]].y,h[a[j]],-1);
		h[a[i]]=Bidimensional_BIT::Get_Ans(mempool[a[i]].x,mempool[a[i]].y,1);
	}
	for(i=1;i<=n&&f[a[i]]==1;i++)
		total+=h[a[i]];
	for(i=1;i<=n;i++)
		printf("%.10lf%c",(double)(g[i]*h[i]/total),i==n?'\n':' ');
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值