【BZOJ2244】【SDOI2011】拦截导弹

来源:互联网 发布:无印良品淘宝旗舰店 编辑:程序博客网 时间:2024/05/17 01:02

Description

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

Input

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

Output

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

Sample Input

43 304 406 603 30

Sample Output

20.33333 0.33333 0.33333 1.00000

数据规模和约定

对于 100% 的数据,1n5×1041hivi109
均匀分布着约 30% 的数据,所有 vi 均相等。
均匀分布着约 50% 的数据,满足 1hivi1000

题解

一道综合数据结构与 DP 的好题。

首先,题目要求求一个最长二维不上升序列的长度,这可以通过 CDQ 分治 + 树状数组解决。转移方式同 O(nlog2n) 的最长不上升子序列。

然后,题目要求求出随机选取一个最初不上升子序列,每个点被选中的概率。这可以通过类似 LIS 计数的方法解决。也是和一维的情况类似,可以在dp的过程中记录以当前位置结束的最长不上升子序列的数量 g(0,i) 和以当前位置开头的最长不上升子序列的数量 g(1,i)g(0,i)×g(1,i) 就是选中当前节点的最长不上升子序列的数量,从而求得概率。

总复杂度 O(nlog22n)

My Code

#include <iostream>#include <cstring>#include <cmath>#include <algorithm>#include <cstdio>using namespace std;typedef long long ll;struct node {    int x, y, id, ans;} d[100005], t[100005];int n;int h[100005], c[100005];int th[100005], tc[100005];int bit[1000005];double cnt[1000005];inline int lowbit(int x) {    return x & -x;}inline void add(int x, int w, double v) {    for(int i = x; i <= n; i += lowbit(i)) {        if(bit[i] == w) {            cnt[i] += v;        } else if(bit[i] < w) {            bit[i] = w;            cnt[i] = v;        }    }}inline int qmax(int x) {    int sum = 0;    for(int i = x; i; i -= lowbit(i)) {        if(bit[i] > sum) sum = bit[i];    }    return sum;}inline double qsum(int x, int mx) {    double sum = 0;    for(int i = x; i; i -= lowbit(i)) {        if(bit[i] == mx) sum += cnt[i];    }    return sum;}inline void del(int x) {    for(int i = x; i <= n; i += lowbit(i)) {        cnt[i] = 0;        bit[i] = 0;    }}int f[2][100005];double g[2][100005];int cmp1(node a, node b) {    return a.x < b.x;}int cmp2(node a, node b) {    return a.id < b.id;}void cdq1(int l, int r) {    if(l == r) return;    int mid = (l + r) >> 1;    cdq1(l, mid);    int p = l, q = mid + 1;    sort(d + l, d + mid + 1, cmp1);    sort(d + mid + 1, d + r + 1, cmp1);    for(int i = l; i <= r; i ++) {        if((p <= mid && d[p].x <= d[q].x) || q > r) {            add(d[p].y, f[0][d[p].id], g[0][d[p].id]);            p++;        } else {            int tmax = qmax(d[q].y);            if(f[0][d[q].id] < tmax + 1) {                f[0][d[q].id] = tmax + 1;                g[0][d[q].id] = qsum(d[q].y, tmax);            } else if(f[0][d[q].id] == tmax + 1) {                g[0][d[q].id] += qsum(d[q].y, tmax);            }            q++;        }    }    for(int i = l; i <= mid; i ++) {        del(d[i].y);    }    sort(d + l, d + r + 1, cmp2);    cdq1(mid + 1, r);    sort(d + l, d + r + 1, cmp2);}void cdq2(int l, int r) {    if(l == r) return;    int mid = (l + r) >> 1;    cdq2(l, mid);    int p = l, q = mid + 1;    sort(d + l, d + mid + 1, cmp1);    sort(d + mid + 1, d + r + 1, cmp1);    for(int i = l; i <= r; i ++) {        if((p <= mid && d[p].x <= d[q].x) || q > r) {            add(d[p].y, f[1][d[p].id], g[1][d[p].id]);            p++;        } else {            int tmax = qmax(d[q].y);            if(f[1][d[q].id] < tmax + 1) {                f[1][d[q].id] = tmax + 1;                g[1][d[q].id] = qsum(d[q].y, tmax);            } else if(f[1][d[q].id] == tmax + 1) {                g[1][d[q].id] += qsum(d[q].y, tmax);            }            q++;        }    }    for(int i = l; i <= mid; i ++) {        del(d[i].y);    }    sort(d + l, d + r + 1, cmp2);    cdq2(mid + 1, r);    sort(d + l, d + r + 1, cmp2);}int main() {    scanf("%d", &n);    for(int i = 1; i <= n; i ++) {        scanf("%d%d", &h[i], &c[i]);        th[i] = h[i];        tc[i] = c[i];    }    sort(th + 1, th + n + 1);    sort(tc + 1, tc + n + 1);    for(int i = 1; i <= n; i ++) {        h[i] = lower_bound(th + 1, th + n + 1, h[i]) - th;        c[i] = lower_bound(tc + 1, tc + n + 1, c[i]) - tc;        d[i].x = n - h[i] + 1, d[i].y = n - c[i] + 1;        d[i].id = i;    }    for(int i = 1; i <= n; i ++) f[0][i] = f[1][i] = g[0][i] = g[1][i] = 1;    cdq1(1, n);    for(int i = 1; i <= n; i ++) {        d[i].x = h[n - i + 1], d[i].y = c[n - i + 1];        d[i].id = i;    }    cdq2(1, n);    int ans = 0;    for(int i = 1; i <= n; i ++) {        ans = max(ans, f[0][i]);    }    printf("%d\n", ans);    double sum = 0;    for(int i = 1; i <= n; i ++) {        if(f[0][i] == ans) sum += g[0][i];    }    for(int i = 1; i <= n; i ++) {        if(f[0][i] + f[1][n - i + 1] - 1 != ans) printf("%.5lf ", 0.0);        else printf("%.5lf ", double(g[0][i]) * double(g[1][n - i + 1]) / sum);    }    return 0;}
原创粉丝点击