• BZOJ 2244: [SDOI2011]拦截导弹 (CDQ分治 三维偏序 DP)


    题意

    略…

    分析

    就是求最长不上升子序列,坐标取一下反就是求最长不下降子序列,比较大小是二维(h,v)(h,v)的比较.我们不看概率,先看第一问怎么求最长不降子序列.设f[i]f[i]表示以ii结尾的最长不降子序列的长度,有f[i]=max(f[j]+1) ( 0j<i,hjhi,vjvi )f[i]=max(f[j]+1) ( 0le j<i,h_jle h_i,v_jle v_i )那这就是一个三维偏序问题,只需要第一维CDQCDQ,第二维排序,第三维用树状数组维护就行了.

    要求概率,再定义g[i]g[i]表示以ii开始的最长不降子序列的长度.要求g[i]g[i]就坐标取反从nn11再做一次DPDP就行了.我们再设[0][0]表示序列长度,[1][1]表示这个长度的序列的方案.那对于ii点在最长不降子序列上的概率就是 f[i][1]g[i][1] ( f[i][0]+g[i][0]1=LIS )1jnf[j][1] ( f[j][0]=LIS )frac{f[i][1]*g[i][1] ( f[i][0]+g[i][0]-1=LIS )}{sum_{1le jle n} f[j][1] ( f[j][0]=LIS )}分母其实就是总的最长上升子序列数量.

    时间复杂度O(nlog2n)O(nlog^2n)
    第一次写这样的CDQCDQ,感觉好强…(是我太菜)

    CODE

    其实CDQCDQ分治和树状数组都要离散化,但是标号本来就是1...n1...n,就只用离散化vv了.

    代码还是蛮短的

    #include <cctype>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    char cb[1<<15],*cs=cb,*ct=cb;
    #define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
    template<class T>inline void read(T &res) {
        char ch; int flg = 1; for(;!isdigit(ch=getchar());)if(ch=='-')flg=-flg;
        for(res=ch-'0';isdigit(ch=getchar());res=res*10+ch-'0'); res*=flg;
    }
    const int MAXN = 50005;
    int n, bin[MAXN], tot, indx, stk[MAXN];
    struct node { //写一个结构体
    	int x; double y; //方案数要用double不然会溢出
    	node() { x = y = 0; }
    	node(int _x, double _y):x(_x), y(_y){}
    	inline bool operator <(const node &o)const { return x < o.x; }
    }T[MAXN];
    inline void chkmax(node &A, const node &B) {
    	if(B < A) return;
    	if(A < B) A = B;
    	else A.y += B.y;
    }
    inline void upd(int x, node val) {
    	while(x <= tot) {
    		if(val.x > T[x].x) { 
    			if(!T[x].x) stk[++indx] = x; //第一次修改就进栈
    			T[x] = val;
    		}
    		else if(val.x == T[x].x) T[x].y += val.y;
    		x += x&-x;
    	}
    }
    inline node qsum(int x) {
    	node res;
    	while(x) chkmax(res, T[x]), x -= x&-x;
    	return res;
    }
    struct Node { int i, h, v; node f; };
    inline bool cmp2(const Node &A, const Node &B) { return A.h == B.h ? A.i < B.i : A.h < B.h; }
    inline bool cmp(const Node &A, const Node &B) { return A.i < B.i; }
    struct CDQ {
    	Node a[MAXN], tmp[MAXN];
    	void cdq(int l, int r) {
    		if(l == r) { if(!a[l].f.x || !a[l].f.y) a[l].f.x = a[l].f.y = 1; return; }
    		int mid = (l + r) >> 1;
    		int L = l, R = mid+1;
    		for(int i = l; i <= r; ++i) //分成左右两边
    			if(a[i].i <= mid) tmp[L++] = a[i];
    			else tmp[R++] = a[i];
    		for(int i = l; i <= r; ++i) a[i] = tmp[i];
    		cdq(l, mid);
    		sort(a + l, a + mid + 1, cmp2); L = l;
    		for(int i = mid+1; i <= r; ++i) {
    			while(L <= mid && a[i].h >= a[L].h) upd(a[L].v, a[L].f), ++L;
    			node res = qsum(a[i].v);
    			if(!res.x) continue;
    			++res.x, chkmax(a[i].f, res);
    		}
    		while(indx) T[stk[indx--]] = node(0, 0); //清零树状数组
    		cdq(mid+1, r);
    	}
    }dp[2];
    int main () {
    	read(n);
    	for(int i = 1; i <= n; ++i) {
    		dp[0].a[i].i = i, read(dp[0].a[i].h), read(dp[0].a[i].v);
    		dp[0].a[i].h *= -1, dp[0].a[i].v *= -1;
    		bin[++tot] = dp[0].a[i].v;
    	}
    	sort(bin + 1, bin + tot + 1); //只离散化V
    	tot = unique(bin + 1, bin + tot + 1) - bin - 1;
    	for(int i = 1; i <= n; ++i) {
    		dp[0].a[i].v = lower_bound(bin + 1, bin + tot + 1, dp[0].a[i].v) - bin;
    		dp[1].a[n-i+1].i = n-i+1;
    		dp[1].a[n-i+1].h = -dp[0].a[i].h;
    		dp[1].a[n-i+1].v = tot-dp[0].a[i].v+1;
    	}
    	sort(dp[0].a + 1, dp[0].a + n + 1, cmp2), dp[0].cdq(1, n); 
    	sort(dp[1].a + 1, dp[1].a + n + 1, cmp2), dp[1].cdq(1, n); //做两次
    	sort(dp[0].a + 1, dp[0].a + n + 1, cmp);
    	sort(dp[1].a + 1, dp[1].a + n + 1, cmp); //重排序为 1~n
    	node Ans;
    	for(int i = 1; i <= n; ++i)
    		chkmax(Ans, dp[0].a[i].f);
    	printf("%d
    ", Ans.x);
    	for(int i = 1; i <= n; ++i)
    		if(dp[0].a[i].f.x + dp[1].a[n-i+1].f.x - 1 < Ans.x) printf("%.6f ", 0.0);
    		else printf("%.6f ", dp[0].a[i].f.y*dp[1].a[n-i+1].f.y/Ans.y);
    	return 0;
    }
    
  • 相关阅读:
    sql 从A表复制数据到B表
    sql union和union all
    sql 类型转换
    SQL聚合函数
    数据存储类型
    asp.net中XML如何做增删改查操作(基础操作)
    数据库分页总结
    javascript 和 jquery 初学总结
    File FileStream StreamReader和StreamWriter
    oracle建数据库
  • 原文地址:https://www.cnblogs.com/Orz-IE/p/12039368.html
Copyright © 2020-2023  润新知