洛谷 P2487 [SDOI2011]拦截导弹

题目描述

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

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

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

输入输出格式

输入格式:

 

 

输出格式:

 

 

输入输出样例

输入样例#1:
4
3 30
4 40
6 60
3 30
输出样例#1:
2
0.33333 0.33333 0.33333 1.00000

说明

题目大意:求二维LDS,以及每个位置在LDS中出现的概率

破题

第14个点大概是有问题

头一次见到用double的计数题

h和v太大了,显然要先离散化

先考虑第一个问题,这是一个三维偏序关系,显然可以cdq分治解决,注意分治的顺序是左中右不是左右中

然后是第二个问题,考虑在cdq分治的时候同时记录一下LDS的个数,那么一个位置出现的概率就是(经过这个位置的LDS数量/总的LDS数量)

怎么求经过一个位置的LDS数量呢,我们考虑倒过来再做一遍二维LIS,显然如果一个位置在某个LDS中,那么 以它结尾的LDS长度+倒过来以它结尾的LIS长度=整个序列的LDS长度+1,而经过这个位置的LDS数量则是 以他结尾的LDS数量*倒过来以他结尾的LIS数量

然而这个东西longlong都存不下,必须开double

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <string>
#include <cstring>
#include <cmath>
#include <map>
#include <stack>
#include <set>
#include <vector>
#include <queue>
#include <time.h>
#define eps 1e-7
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define rep0(j,n) for(int j=0;j<n;++j)
#define rep1(j,n) for(int j=1;j<=n;++j)
#define pb push_back
#define mp make_pair
#define set0(n) memset(n,0,sizeof(n))
#define ll long long
#define ull unsigned long long
#define iter(i,v) for(edge *i=head[v];i;i=i->nxt)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define print_runtime printf("Running time:%.3lfs\n",double(clock())/1000.0)
#define TO(j) printf(#j": %d\n",j);
//#define OJ
using namespace std;
const int MAXINT = 50010;
const int MAXNODE = 100010;
const int MAXEDGE = 2 * MAXNODE;
char BUF, *buf;
int read() {
    char c = getchar(); int f = 1, x = 0;
    while (!isdigit(c)) { if (c == '-') f = -1; c = getchar(); }
    while (isdigit(c)) { x = x * 10 + c - '0'; c = getchar(); }
    return f * x;
}
char get_ch() {
    char c = getchar();
    while (!isalpha(c)) c = getchar();
    return c;
}
//------------------- Head Files ----------------------//


int n, b[MAXINT], cnt_b, c[MAXINT], cnt_c;
double prop[MAXINT];
struct res {
    int v;
    double cnt;
    res(int _v, double _c) : v(_v), cnt(_c) {}
    res() {}
};
res add(res a, res b) {
    if (a.v == b.v) return res(a.v, a.cnt + b.cnt);
    if (a.v > b.v) return a;
    else return b;
}
struct missile {
    int h, v, id;
    res ans;
} a[MAXINT], s[MAXINT];
struct node {
    int lb, rb;
    res ans;
    int tag;
    node *l, *r;
    void pushup() {
        ans = add(l->ans, r->ans);
    }
    void clear() {
        ans = res(-1, -1);
        tag = 0;
    }
    void pushdown() {
        if (tag != -1) {
            l->clear();
            r->clear();
            tag = -1;
        }
    }
};

struct SegTree {
    node mp[MAXINT * 4];
    node *root;
    int cnt;
    node *newnode(int l, int r) {
        node *p = &mp[cnt++];
        p->lb = l; p->rb = r;
        return p;
    }
    void buildtree(int l, int r, node *&p) {
        p = newnode(l, r);
        if (r - l > 1) {
            buildtree(l, (l + r) / 2, p->l);
            buildtree((l + r) / 2, r, p->r);
        }
    }
    void clear() {
        root->clear();
    }
    void insert(int pos, res v) {
        insert(pos, v, root);
    }
    void insert(int pos, res v, node *p) {
        if (p->rb - p->lb == 1) {
            p->ans = add(p->ans, v);
            return;
        }
        p->pushdown();
        int mid = (p->lb + p->rb) / 2;
        if (pos < mid) insert(pos, v, p->l);
        else        insert(pos, v, p->r);
        p->pushup();
    }
    res query(int l) {
        res ret = query(l, INF, root);
        ret.v++;
        return ret;
    }
    res query2(int r) {
        res ret = query(0, r + 1, root);
        ret.v++;
        return ret;
    }
    res query(int l, int r, node *p) {
        if (r <= p->lb || l >= p->rb) return res(-1, -1);
        if (r >= p->rb && l <= p->lb) return p->ans;
        p->pushdown();
        return add(query(l, r, p->l), query(l, r, p->r));
    }
} st;
bool cmph(const missile & a, const missile & b) {
    return a.h > b.h;
}
bool cmph2(const missile & a, const missile & b) {
    return a.h < b.h;
}
bool cmpid(const missile & a, const missile & b) {
    return a.id < b.id;
}
bool cmpid2(const missile & a, const missile & b) {
    return a.id > b.id;
}
void cdq(int l, int r) {
    int mid = (l + r) / 2;
    if (r - l == 1) return;
    sort(a + l, a + r, cmpid);
    cdq(l, mid);
    sort(a + l, a + mid, cmph);
    sort(a + mid, a + r, cmph);

    int mx = 0, cnt = 0, i = l, j = mid;
    st.clear();
    for (; i < mid; i++) {
        for (; j < r && a[j].h > a[i].h; j++) {
            a[j].ans = add(a[j].ans, st.query(a[j].v));
        }
        st.insert(a[i].v, a[i].ans);
    }
    for (; j < r; j++) {
        a[j].ans = add(a[j].ans, st.query(a[j].v));
    }
    cdq(mid, r);
}
void cdq2(int l, int r) {
    int mid = (l + r) / 2;
    if (r - l == 1) return;
    sort(s + l, s + r, cmpid2);
    cdq2(l, mid);
    sort(s + l, s + mid, cmph2);
    sort(s + mid, s + r, cmph2);

    int mx = 0, cnt = 0, i = l, j = mid;
    st.clear();
    for (; i < mid; i++) {
        for (; j < r && s[j].h < s[i].h; j++) {
            s[j].ans = add(s[j].ans, st.query2(s[j].v));
        }
        st.insert(s[i].v, s[i].ans);
    }
    for (; j < r; j++) {
        s[j].ans = add(s[j].ans, st.query2(s[j].v));
    }
    cdq2(mid, r);
}
void get_input();
void work();
int main() {
    get_input();
    work();
    return 0;
}

void work() {
    st.buildtree(0, n, st.root);
    rep0(i, n) s[i] = a[i];
    sort(s, s + n, cmpid2);
    cdq(0, n);
    cdq2(0, n);
    res ans(0, 0);
    rep0(i, n) {
        ans = add(ans, a[i].ans);
    }

    sort(a, a + n, cmpid);
    sort(s, s + n, cmpid);
    rep0(i, n) {
        if (s[i].ans.v + a[i].ans.v != ans.v + 1) prop[i] = 0; else {
            prop[i] = s[i].ans.cnt*a[i].ans.cnt / double(ans.cnt);
        }
    }
    printf("%lld\n", ans.v);
    rep0(i, n) printf("%.5lf ", prop[i]);
    putchar('\n');
}
void get_input() {
    n = read();
    rep0(i, n) {
        a[i].id = i;
        a[i].h = read(); a[i].v = read(); a[i].ans = res(1, 1);
        b[cnt_b++] = a[i].h;
        c[cnt_c++] = a[i].v;
    }
    sort(b, b + cnt_b);
    sort(c, c + cnt_c);
    cnt_b = unique(b, b + cnt_b) - b;
    cnt_c = unique(c, c + cnt_c) - c;
    rep0(i, n) {
        a[i].h = lower_bound(b, b + cnt_b, a[i].h) - b;
        a[i].v = lower_bound(c, c + cnt_c, a[i].v) - c;
    }
}

 

转载于:https://www.cnblogs.com/LoveYayoi/p/6916104.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值