zoukankan      html  css  js  c++  java
  • BZOJ2244 [SDOI2011]拦截导弹 【cdq分治 + 树状数组】

    题目

    某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。
    在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。
    我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。

    输入格式

    第一行包含一个正整数n,表示敌军导弹数量;
    下面 行按顺序给出了敌军所有导弹信息:
    第i+1行包含2个正整数hi和vi,分别表示第 枚导弹的高度和速度。

    输出格式

    输出包含两行。
    第一行为一个正整数,表示最多能拦截掉的导弹数量;
    第二行包含n个0到1之间的实数,第i个数字表示第i枚导弹被拦截掉的概率(你可以保留任意多位有效数字)。

    输入样例

    4

    3 30

    4 40

    6 60

    3 30

    输出样例

    2

    0.33333 0.33333 0.33333 1.00000

    提示

    对于100%的数据,1≤n≤5*104, 1≤hi ,vi≤109;

    均匀分布着约30%的数据,所有vi均相等。

    均匀分布着约50%的数据,满足1≤hi ,vi≤1000。

    题解

    二维LIS
    考虑cdq分治,套上树状数组可以得到答案

    但是要算概率就有些麻烦了
    先要算出总方案数,计算过程中记录,最后最大值的地方方案数之和就是总方案数

    至于每个点有多少方案经过
    我们反着再做一次LIS,这样一个点往前往后之和 - 1如果等于答案,那么就将往前往后方案数乘起来就是总的方案数

    码着真tm累

    #include<iostream>
    #include<cstdio>
    #include<cmath>
    #include<map>
    #include<cstring>
    #include<algorithm>
    #define LL long long int
    #define Redge(u) for (int k = h[u],to; k; k = ed[k].nxt)
    #define REP(i,n) for (int i = 1; i <= (n); i++)
    #define BUG(s,n) for (int i = 1; i <= (n); i++) cout<<s[i]<<' '; puts("");
    #define lbt(x) (x & -x)
    #define mp(a,b) make_pair<double,double>(a,b)
    #define cp pair<double,double>
    using namespace std;
    const int maxn = 50005,maxm = 100005,INF = 1000000000;
    inline int read(){
    	int out = 0,flag = 1; char c = getchar();
    	while (c < 48 || c > 57){if (c == '-') flag = -1; c = getchar();}
    	while (c >= 48 && c <= 57){out = (out << 3) + (out << 1) + c - 48; c = getchar();}
    	return out * flag;
    }
    struct node{int t,x,y; double f[2],g[2];}e[maxn],t[maxn];
    inline bool operator <(const node& a,const node& b){
    	return a.x == b.x ? a.y < b.y : a.x < b.x;
    }
    inline bool cmp(const node& a,const node& b){
    	return a.t < b.t;
    }
    int b[maxn],tot,c[maxn],tt;
    int getx(int x){return lower_bound(b + 1,b + 1 + tot,x) - b;}
    int gety(int x){return lower_bound(c + 1,c + 1 + tt,x) - c;}
    int n;
    double mx[maxn],sum[maxn];
    void upd(int u,double v,double s){
    	while (u <= tt){
    		if (v > mx[u]){
    			mx[u] = v;
    			sum[u] = s;
    		}
    		else if (v == mx[u])
    			sum[u] += s;
    		u += lbt(u);
    	}
    }
    cp query(int u){
    	cp re = mp(0,0);
    	while (u){
    		if (mx[u] > re.first){
    			re.first = mx[u];
    			re.second = sum[u];
    		}
    		else if (mx[u] == re.first)
    			re.second += sum[u];
    		u -= lbt(u);
    	}
    	return re;
    }
    void cls(int u){
    	while (u <= tt){
    		sum[u] = mx[u] = 0;
    		u += lbt(u);
    	}
    }
    void init(){
    	n = read();
    	for (int i = 1; i <= n; i++){
    		e[i].t = i;
    		e[i].x = b[i] = read();
    		e[i].y = c[i] = read();
    	}
    	sort(b + 1,b + 1 + n);
    	sort(c + 1,c + 1 + n);
    	tot = tt = 1;
    	for (int i = 2; i <= n; i++) if (b[i] != b[tot]) b[++tot] = b[i];
    	for (int i = 2; i <= n; i++) if (c[i] != c[tt]) c[++tt] = c[i];
    	for (int i = 1; i <= n; i++){
    		e[i].x = getx(e[i].x);
    		e[i].y = gety(e[i].y);
    	}
    }
    void cdq(int l,int r,int p){
    	if (l == r){
    		if (!e[l].f[p]) e[l].f[p] = e[l].g[p] = 1;
    		return;
    	}
    	int mid = l + r >> 1,li = l,ri = mid + 1;
    	for (int i = l; i <= r; i++){
    		if (e[i].t <= mid) t[li++] = e[i];
    		else t[ri++] = e[i];
    	}
    	for (int i = l; i <= r; i++) e[i] = t[i];
    	cdq(l,mid,p);
    	sort(e + l,e + mid + 1);
    	cp tmp; li = l; ri = mid + 1;
    	while (li <= mid && ri <= r){
    		if (e[li].x <= e[ri].x) upd(e[li].y,e[li].f[p],e[li].g[p]),li++;
    		else {
    			tmp = query(e[ri].y);
    			if (!tmp.first) {ri++; continue;}
    			if (tmp.first + 1 > e[ri].f[p]){
    				e[ri].f[p] = tmp.first + 1;
    				e[ri].g[p] = tmp.second;
    			}
    			else if (tmp.first + 1 == e[ri].f[p]){
    				e[ri].g[p] += tmp.second;
    			}
    			ri++;
    		}
    	}
    	while (ri <= r){
    		tmp = query(e[ri].y);
    		if (!tmp.first) {ri++; continue;}
    		if (tmp.first + 1 > e[ri].f[p]){
    			e[ri].f[p] = tmp.first + 1;
    			e[ri].g[p] = tmp.second;
    		}
    		else if (tmp.first + 1 == e[ri].f[p]){
    			e[ri].g[p] += tmp.second;
    		}
    		ri++;
    	}
    	for (int i = l; i < li; i++) cls(e[i].y);
    	cdq(mid + 1,r,p);
    }
    void solve(){
    	for (int i = 1; i <= n; i++){
    		e[i].x = tot - e[i].x + 1;
    		e[i].y = tt - e[i].y + 1;
    	}
    	sort(e + 1,e + 1 + n);
    	cdq(1,n,0);
    	for (int i = 1; i <= n; i++){
    		e[i].x = tot - e[i].x + 1;
    		e[i].y = tt - e[i].y + 1;
    		e[i].t = n - e[i].t + 1;
    	}
    	sort(e + 1,e + 1 + n);
    	cdq(1,n,1);
    	for (int i = 1; i <= n; i++) e[i].t = n - e[i].t + 1;
    	sort(e + 1,e + 1 + n,cmp);
    	double ans = 0,sum = 0;
    	for (int i = 1; i <= n; i++){
    		if (e[i].f[0] > ans){
    			ans = e[i].f[0];
    			sum = e[i].g[0];
    		}else if (e[i].f[0] == ans){
    			sum += e[i].g[0];
    		}
    	}
    	printf("%.lf
    ",ans);
    	for (int i = 1; i <= n; i++){
    		if (e[i].f[0] + e[i].f[1] - 1 < ans) printf("0 ");
    		else printf("%.6lf ",e[i].g[0] * e[i].g[1] / sum);
    	}
    }
    int main(){
    	init();
    	solve();
    	return 0;
    }
    
    
  • 相关阅读:
    70.BOM
    69.捕获错误try catch
    68.键盘事件
    523. Continuous Subarray Sum
    901. Online Stock Span
    547. Friend Circles
    162. Find Peak Element
    1008. Construct Binary Search Tree from Preorder Traversal
    889. Construct Binary Tree from Preorder and Postorder Traversal
    106. Construct Binary Tree from Inorder and Postorder Traversal
  • 原文地址:https://www.cnblogs.com/Mychael/p/8580956.html
Copyright © 2011-2022 走看看