AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 2506. 拦截导弹    原题链接    困难

作者: 作者的头像   Conan15 ,  2025-06-10 19:39:51 · 福建 ,  所有人可见 ,  阅读 32


1


省流:简单题,但是代码出锅写了半天。

先考虑第一问,若 $i \lt j, a_i \leq a_j, b_i \leq b_j$ 则建边 $i \to j$,求最长路径。
这是好做的,显然三维偏序。
然后第二问:对于每一个节点 $i$,求 $i$ 在路径上的概率。

保证总方案数不超过 C++ 中 double 类型的存储范围。

所以直接用 double 存总方案数即可,再设 $f_i, g_i$ 表示 $1 \to i$ 和 $i \to end$ 的方案数,显然这两段路径都要长度极大。
然后一样地三维偏序过程中记录方案数之和即可。

具体实现:分别正反做 cdq 分治,按照正常三维偏序的板子套计数即可。
一开始方案数忘记加上第三维的限制了(只拿了一个桶记)所以要把它和最大值一起扔一个 pair 维护。

#include <bits/stdc++.h>
#define PID pair<int, double>
using namespace std;
const int N = 5e4 + 5;
int n, X[N], Y[N];
struct node { int id, a, b, dis; double c; } a[N];
inline bool cmpid(node a, node b) { return a.id < b.id; }
inline bool cmpa1(node a, node b) { return a.a > b.a; }
inline bool cmpa2(node a, node b) { return a.a < b.a; }

PID tr[N];      // 树状数组 -- Max of dist、方案数 cnt
PID merge(PID a, int d, double c) {
    if (d < a.first) return a;
    if (d == a.first) return {a.first, a.second + c};
    return {d, c};
}
inline void add(int x, int d, double c) { for ( ; x ; x -= x & -x) tr[x] = merge(tr[x], d, c); }
inline PID query(int x) { PID res = {0, 0}; for ( ; x < N ; x += x & -x) res = merge(res, tr[x].first, tr[x].second); return res; }
inline void clr(int x, int d) { for ( ; x ; x -= x & -x) tr[x] = {0, 0}; }

void cdq1(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    cdq1(l, mid);

    sort(a + l, a + mid + 1, cmpa1);
    sort(a + mid + 1, a + r + 1, cmpa1);
    for (int i = l, j = mid + 1, k = l; k <= r; k++) {
        if ((j > r) || (i <= mid && a[i].a >= a[j].a)) add(a[i].b, a[i].dis, a[i].c), i++;
        else {              
            auto [Max, cnt] = query(a[j].b);    // 左边能提供的最长长度
            if (Max + 1 > a[j].dis) a[j].dis = Max + 1, a[j].c = cnt;
            else if (Max + 1 == a[j].dis) a[j].c += cnt;
            j++;
        }
    }
    for (int i = l; i <= mid; i++) clr(a[i].b, a[i].dis);
    sort(a + mid + 1, a + r + 1, cmpid);

    cdq1(mid + 1, r);
}

inline void add2(int x, int d, double c) { for ( ; x < N; x += x & -x) tr[x] = merge(tr[x], d, c); }
inline PID query2(int x) { PID res = {0, 0}; for ( ; x ; x -= x & -x) res = merge(res, tr[x].first, tr[x].second); return res; }
inline void clr2(int x, int d) { for ( ; x < N ; x += x & -x) tr[x] = {0, 0}; }

void cdq2(int l, int r) {
    if (l == r) return;
    int mid = l + r >> 1;
    cdq2(mid + 1, r);

    sort(a + l, a + mid + 1, cmpa2);
    sort(a + mid + 1, a + r + 1, cmpa2);
    for (int i = l, j = mid + 1, k = l; k <= r; k++) {
        if ((i > mid) || (j <= r && a[i].a >= a[j].a)) add2(a[j].b, a[j].dis, a[j].c), j++;
        else {
            auto [Max, cnt] = query2(a[i].b);    // 左边能提供的最长长度
            if (Max + 1 > a[i].dis) a[i].dis = Max + 1, a[i].c = cnt;
            else if (Max + 1 == a[i].dis) a[i].c += cnt;
            i++;
        }
    }
    for (int i = mid + 1; i <= r; i++) clr2(a[i].b, a[i].dis);
    sort(a + l, a + mid + 1, cmpid);

    cdq2(l, mid);
}

double all, ans[N];
int dist[N];

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; i++) scanf("%d%d", &a[i].a, &a[i].b), a[i].dis = 1, a[i].c = 1, a[i].id = i, X[i] = a[i].a, Y[i] = a[i].b;
    sort(X + 1, X + 1 + n), sort(Y + 1, Y + 1 + n);
    int m1 = unique(X + 1, X + 1 + n) - X - 1, m2 = unique(Y + 1, Y + 1 + n) - Y - 1;
    for (int i = 1; i <= n; i++) a[i].a = lower_bound(X + 1, X + 1 + m1, a[i].a) - X, a[i].b = lower_bound(Y + 1, Y + 1 + m2, a[i].b) - Y;

    cdq1(1, n);
    sort(a + 1, a + 1 + n, cmpid);
    // for (int i = 1; i <= n; i++) cout << a[i].dis << ' '; puts("");
    int Max = 0; for (int i = 1; i <= n; i++) Max = max(Max, a[i].dis), dist[i] = a[i].dis;
    printf("%d\n", Max);
    for (int i = 1; i <= n; i++) {
        ans[i] = a[i].c;
        if (a[i].dis == Max) all += a[i].c;
        a[i].c = 1, a[i].dis = 1;
    }

    cdq2(1, n);
    sort(a + 1, a + 1 + n, cmpid);
    // for (int i = 1; i <= n; i++) cout << a[i].dis << ' '; puts("");
    for (int i = 1; i <= n; i++) 
        if ((dist[i] + a[i].dis - 1) ^ Max) printf("0.00000 ");
        else printf("%.5lf ", ans[i] * a[i].c / all);
    return 0;
}

0 评论

App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息