• CDQ分治优化一维DP转移——[SDOI2011]拦截导弹


    在这之前P1020 导弹拦截

    Description [SDOI2011]拦截导弹

    给出(n)个导弹,每个导弹三个属性(t_i,h_i,v_i),分别为时间,发射高度,速度。对于已经拦截的导弹 (i),下一个能被拦截的导弹(j)必须满足(i<j,h_igeq h_j,v_igeq v_j),请求出最多能拦截的导弹数量。对此,可能有多种方案,请再求出每个导弹被拦截的概率。

    Solution

    显然这是一个DP的题目。根据题意,可以得到DP方程(dp_i=1+max(dp[j],forall i>j,h_jgeq h_i,v_jgeq v_i)),对于这个方程普通的DP需要时间(O(n^2)),需要优化,我们注意到后面三个条件类似于三维偏序,所以我们考虑

    CDP分治优化一维DP转移

    先考虑CDQ是什么。(我想只有我不知道),一种广泛的用法是处理点对有关问题,详情OI-Wiki-part1

    对于普通的CDQ,处理区间((l,r))顺序是这样的:

    1.处理区间 ((l,mid))

    2.处理区间((mid+1,r))

    3.处理(lleq ileq mid,mid+1leq j leq r)的关系

    但是对于CDQ优化DP转移,我们需要顺序:1、3、2。

    为什么呢?我们考虑DP顺序,对于正在更新的位置(i),我们需要将所有位置在它前面的值都更新完毕,所以需要先更新整个区间再更新其他的区间。

    解决了优化DP的问题,我们可以求一个最长不升子序列就能得到第一问的答案。对于第二问,我们考虑记录总的方案数,用经过一个点的方案数除以总方案数(sum)就是答案。

    考虑对于一个点(i),如果它在目标序列中却不是目标序列的终点,我们需要知道在它后面还有多少方案数能够到达目标序列,那么就可以将整个序列取反(就是大的变小小的变大)再求一遍最长不升子序列就能知道在它后面的方案数(a[1][i].gl),那么((a[0][i].gl*a[1][i].gl)/sum)就可以得到这个点出现的概率了。

    Code(有注释在代码里)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define db double//不开double会炸qwq
    #define int long long
    using namespace std;
    const int N=5e4+5;
    struct node {
    	int h,v,ans,id;//ans表示以点i为结尾的最长不升子序列长度,gl为方案数
    	db gl;
    }a[2][N];//a[0]是正着的,a[1]是反着的
    int n,ls[N],tot;
    
    struct Tree1{
    	int mx[N];
    	db gl[N];
    
    	inline void add (int x,int maxx,db g) {
    		while (x) {
    			if (maxx==mx[x])	gl[x]+=g;
    			else if(maxx>mx[x]) mx[x]=maxx,gl[x]=g;
    			x-=x&(-x);
    		}
    	}
    
    	inline void query (int x,int &mxx,db &g) {
    		while (x<=tot) {
    			if (mxx==mx[x]) g+=gl[x];
    			else	if (mxx<mx[x])	mxx=mx[x],g=gl[x];
    			x+=x&(-x);
    		}
    	}
    
    	inline void del (int x) {
    		while (x) {
    			mx[x]=gl[x]=0;
    			x-=x&(-x);
    		}
    	}
    }T;//树状数组求后缀
    
    inline bool cmpid (node x,node y) {return x.id<y.id;}
    inline bool cmph (node x,node y) {return x.h>y.h;}
    inline bool cmp (node x,node y)	{return x.id>y.id;}
    
    inline void cdq (int l,int r,int ty) {
    	if (l==r)	return;
    	int mid=(l+r)>>1;
    	cdq(l,mid,ty);
    	sort(a[ty]+mid+1,a[ty]+r+1,cmph);
    	int i=l,j=mid+1;
    	while (j<=r) {
    		while (a[ty][i].h>=a[ty][j].h&&i<=mid) {
    			T.add(a[ty][i].v,a[ty][i].ans,a[ty][i].gl);
    			i++;
    		}
    		int mx=0;db g=0;
    		T.query(a[ty][j].v,mx,g);
    		if (mx+1==a[ty][j].ans)	a[ty][j].gl+=g;
    		else if (mx+1>a[ty][j].ans)	a[ty][j].gl=g,a[ty][j].ans=mx+1;
    		j++;
    	}
    	i=l;
    	while (i<=mid)	T.del(a[ty][i].v),i++;//memset会超时,这里需要清空所以del直接归0就好了
    	sort(a[ty]+mid+1,a[ty]+r+1,cmpid);
    	cdq(mid+1,r,ty);
    	sort(a[ty]+l,a[ty]+r+1,cmph);
    }
    
    inline void init () {
    	for (int i=1;i<=n;i++)	ls[i]=a[0][i].v;
    	sort(ls+1,ls+n+1);
    	tot=unique(ls+1,ls+n+1)-ls-1;
    	for (int i=1;i<=n;i++)	a[0][i].v=lower_bound(ls+1,ls+tot+1,a[0][i].v)-ls;
    	for (int i=1;i<=n;i++)	a[1][i]=a[0][i];
    }
    
    signed main () {
    #ifndef ONLINE_JUDGE
    	freopen("2487.in","r",stdin);
    	freopen("2487.out","w",stdout);
    #endif
    	scanf("%lld",&n);
    	for (int i=1;i<=n;i++){
    		scanf("%lld%lld",&a[0][i].h,&a[0][i].v);
    		a[0][i].id=i;a[0][i].ans=a[0][i].gl=1;
    	}
    	init();
    	sort(a[0]+1,a[0]+n+1,cmpid);
    	cdq(1,n,0);
    	int ans_mx=0;db sum=0;
    	for (int i=1;i<=n;i++)	ans_mx=max(ans_mx,a[0][i].ans);
    	printf("%lld
    ",ans_mx);
    	for (int i=1;i<=n;i++)	a[1][i].id=n-a[1][i].id+1,a[1][i].h*=-1,a[1][i].v=tot-a[1][i].v+1;//取反
    	sort(a[1]+1,a[1]+n+1,cmpid);
    	memset(T.mx,0,sizeof(T.mx));
    	memset(T.gl,0,sizeof(T.gl));
    	cdq(1,n,1);
    	for (int i=1;i<=n;i++) 
    		if (a[0][i].ans==ans_mx)	sum+=a[0][i].gl;//只有最长的终点的方案数才统计进总的方案数
    	sort(a[1]+1,a[1]+n+1,cmp);
    	sort(a[0]+1,a[0]+n+1,cmpid);
    	for (int i=1;i<=n;i++) {
    		if (a[1][i].ans+a[0][i].ans-1==ans_mx)	printf("%.5lf ",a[1][i].gl*a[0][i].gl/sum);
    		else printf("0.00000 ");
    	}
    	return 0;
    }
    
  • 相关阅读:
    分享我设计的iOS项目目录结构
    swift语言之多线程操作和操作队列(下)———坚持51天吃掉大象(写技术文章)
    swift语言之多线程操作和操作队列(上)———坚持51天吃掉大象
    获取UIColor中的RGB值(本人亲测多个获取RGB值的方法,这个最有效)
    swift语言开发的一个游戏------熊猫跑酷(KongfuPanda)
    ios上传应用后,审核流程完成前(reveiw)修改了程序内容,如何上传替换
    上架app 到app store 的出现: “The IPA is invalid. It does not inlude a Payload directory.”错误处理
    ios 8+ (xcode 6.0 +)应用程序Ad Hoc 发布前多设备测试流程详解
    Swift 实现iOS Animation动画教程
    新浪微博项目---首页技术点三.上拉刷新,下拉加载的实现(使用ios自带的小菊花实现)
  • 原文地址:https://www.cnblogs.com/FridayZ/p/13849484.html
Copyright © 2020-2023  润新知