「Luogu P2487 && BZOJ 2244」拦截导弹

谁说我不能喝 提交于 2020-02-01 02:23:31

某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度、并且能够拦截任意速度的导弹,但是以后每一发炮弹都不能高于前一发的高度,其拦截的导弹的飞行速度也不能大于前一发。某天,雷达捕捉到敌国的导弹来袭。由于该系统还在试用阶段,所以只有一套系统,因此有可能不能拦截所有的导弹。

在不能拦截所有的导弹的情况下,我们当然要选择使国家损失最小、也就是拦截导弹的数量最多的方案。但是拦截导弹数量的最多的方案有可能有多个,如果有多个最优方案,那么我们会随机选取一个作为最终的拦截导弹行动蓝图。

我方间谍已经获取了所有敌军导弹的高度和速度,你的任务是计算出在执行上述决策时,每枚导弹被拦截掉的概率。

Luogu

BZOJ

分析

这道题,恶心至极。

调了一天......

从我第一次提交到 AC 的时间可以看出我调了多久,还不包括连样例都没过的时候。

第一问就是一个 dp 最大值,但它是三维的,我们可以用 CDQ 来解决。

麻烦在于第二问。

显然,一个点被选到的概率为经过改点的路径条数 / 在 LIS 上的总路径条数,而判断这个点是否在 LIS 上,我们可以通过对正反两面分别 CDQ 一次,求出 dp 值 f[i] ,并记录路径条数 g[i] 。

如果当前节点满足 \(f[i][0]+f[i][1]-1=\max f[j][0](j\in [1,n])\) ,这里的 -1 是去掉对改节点的重复计算,那么它被选中的概率为 \(\frac{g[i][0]\times g[i][1]}{\sum_{j\in LIS}{g[j][0]}}\)

复杂度:\(O(n\log n)\)

代码

CDQ 内 sort 函数一定要这样写(想一想,为什么?)

为什么我也不知道,通过不断的调试发现只有这样写才能对。

//=========================
//  author:hliwen
//  date:2020.2.1
//=========================
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 50003
#define DEBUG puts("ok")
#define tie0 cin.tie(0),cout.tie(0)
#define fastio ios::sync_with_stdio(false)
#define File(x) freopen(x".in","r",stdin);freopen(x".out","w",stdout)
using namespace std;
typedef double db;
typedef long long ll;

template <typename T> inline void read(T &x) {
    T f = 1; x = 0; char c;
    for (c = getchar(); !isdigit(c); c = getchar()) if (c == '-') f = -1;
    for ( ; isdigit(c); c = getchar()) x = x * 10 + (c ^ 48);
    x *= f;
}

struct ele {
    int h, v, id, f[2];
    db g[2];
} e[N], r[N];

db sum;
int n, ans;
int hh[N], hv[N];

struct TreeArray {
    int f[N]; db g[N];

    int lowbit(int i) { return i & -i; }

    void update(int i, int k, db c) {
        while (i <= n) {
            if (f[i] < k) f[i] = k, g[i] = c;
            else if (f[i] == k) g[i] += c;
            i += lowbit(i);
        }
    }

    int query(int i, db &c) {
        int ret = 0; c = 0;
        while (i) {
            if (f[i] > ret) ret = f[i], c = g[i];
            else if (f[i] == ret) c += g[i];
            i -= lowbit(i);
        }
        return ret;
    }

    void del(int i) {
        while (i <= n) {
            f[i] = 0, g[i] = 0;
            i += lowbit(i);
        }
    }
} tr;

bool cmpid(ele x, ele y) { return x.id < y.id; }
bool cmph(ele x, ele y) { return x.h < y.h; }

void CDQ(int l, int r, int opt) {
    if (l == r) return;
    int mid = l + r >> 1;
    sort(&e[l], &e[r+1], cmpid);
    CDQ(l, mid, opt);
    sort(&e[l], &e[mid+1], cmph), sort(&e[mid+1], &e[r+1], cmph);
    int i, j;
    for (i = l, j = mid + 1; j <= r; ++j) {
        while (i <= mid && e[i].h <= e[j].h) tr.update(e[i].v, e[i].f[opt], e[i].g[opt]), i++;
        int x; db y;
        x = tr.query(e[j].v, y) + 1;
        if (x > e[j].f[opt]) e[j].f[opt] = x, e[j].g[opt] = y;
        else if (x == e[j].f[opt]) e[j].g[opt] += y;
    }
    for (i = l; i <= mid; ++i) tr.del(e[i].v);
    CDQ(mid + 1, r, opt);
}

int main() {
    read(n);
    for (int i = 1; i <= n; ++i) {
        read(e[i].h), read(e[i].v), e[i].id = i;
        hh[i] = e[i].h, hv[i] = e[i].v;
        e[i].f[0] = e[i].f[1] = 1;
        e[i].g[0] = e[i].g[1] = 1.0;
    }
    int x, y;
    sort(hh + 1, hh + 1 + n), sort(hv + 1, hv + 1 + n);
    x = unique(hh + 1, hh + 1 + n) - hh - 1, y = unique(hv + 1, hv + 1 + n) - hv - 1;
    for (int i = 1; i <= n; ++i) {
        e[i].h = x - (lower_bound(hh + 1, hh + 1 + x, e[i].h) - hh) + 1;
        e[i].v = y - (lower_bound(hv + 1, hv + 1 + y, e[i].v) - hv) + 1;
    }
    CDQ(1, n, 0);
    sort(e + 1, e + 1 + n, cmpid);
    reverse(e + 1, e + 1 + n);
    for (int i = 1; i <= n; ++i) {
        e[i].id = i;
        e[i].h = x + 1 - e[i].h, e[i].v = y + 1 - e[i].v;
        if (ans < e[i].f[0]) ans = e[i].f[0], sum = e[i].g[0];
        else if (ans == e[i].f[0]) sum += e[i].g[0];
    }
    CDQ(1, n, 1);
    sort(e + 1, e + 1 + n, cmpid);
    printf("%d\n", ans);
    for (int i = n; i; --i) {
        if (e[i].f[0] + e[i].f[1] - 1 == ans) printf("%.5f ", e[i].g[0] * e[i].g[1] / sum);
        else printf("0.00000 ");
    }
    return 0;
}

以下是带调试代码的版本

Code

可以看出我的调试方法有多低级了.......(我连 gdb 都不会)

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!