【LG2481】[SDOI2011]拦截导弹

【LG2481】[SDOI2011]拦截导弹

题面

洛谷

题解

可以看出第一问就是一个有关偏序的\(LIS\),很显然可以用\(CDQ\)优化
关键在于第二问
概率\(P_i=\) \(总LIS数\) / \(经过i的LIS数\)
分别正反跑两遍\(CDQ\)可以统计出分别以\(i\)为终点和起点的\(LIS\)
乘起来就是经过\(i\)的方案数
比较坑的一点是\(long\) \(long\)存不下,要用\(double\)
代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <vector> 
using namespace std;
namespace IO { 
    const int BUFSIZE = 1 << 20; 
    char ibuf[BUFSIZE], *is = ibuf, *it = ibuf; 
    inline char gc() { 
        if (is == it) it = (is = ibuf) + fread(ibuf, 1, BUFSIZE, stdin); 
        return *is++; 
    } 
} 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (ch != '-' && (ch > '9' || ch < '0')) ch = IO::gc();
    if (ch == '-') w = -1 , ch = IO::gc();
    while (ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = IO::gc();
    return w * data;
} 
const int MAX_N = 50005; 
struct Node {int h, v, i; } t[MAX_N]; int N; 
bool cmp_h(const Node &a, const Node &b) { return a.h > b.h; } 
bool cmp_v(const Node &a, const Node &b) { return a.v > b.v; } 
bool cmp_i(const Node &a, const Node &b) { return a.i < b.i; } 

inline int lb(int x) { return x & -x; } 
int c[MAX_N]; double w[MAX_N]; 
void add(int x, int v, double W) { 
    while (x <= N) { 
        if (v == c[x]) w[x] += W; 
        else if (v > c[x]) c[x] = v, w[x] = W; 
        x += lb(x); 
    } 
} 
int sum(int x) { 
    int res = 0;
    while (x > 0) res = max(res, c[x]), x -= lb(x); 
    return res; 
} 
double sum(int x, int v) { 
    double res = 0; 
    while (x > 0) res += (c[x] == v) ? w[x] : 0, x -= lb(x); 
    return res; 
} 
void Set(int x) { while (x <= N) c[x] = w[x] = 0, x += lb(x); } 

int f[2][MAX_N]; double g[2][MAX_N]; 
void Div(int l, int r, int type) { 
    if (l == r) return ; 
    sort(&t[l], &t[r + 1], cmp_i); 
    if (type) reverse(&t[l], &t[r + 1]); 
    int mid = (l + r) >> 1; 
    Div(l, mid, type); 
    sort(&t[l], &t[mid + 1], cmp_h); 
    sort(&t[mid + 1], &t[r + 1], cmp_h); 
    int j = l; 
    for (int i = mid + 1; i <= r; i++) { 
        while (j <= mid && t[j].h >= t[i].h) 
            add(N + 1 - t[j].v, f[type][t[j].i], g[type][t[j].i]), ++j; 
        int res = sum(N + 1 - t[i].v) + 1; 
        if (res > f[type][t[i].i]) 
            f[type][t[i].i] = res, g[type][t[i].i] = sum(N + 1 - t[i].v, res - 1); 
        else if (res == f[type][t[i].i]) g[type][t[i].i] += sum(N + 1 - t[i].v, res - 1); 
    } 
    for (int i = l; i <= mid; i++) Set(N + 1 - t[i].v); 
    Div(mid + 1, r, type); 
} 
int Sh[MAX_N], toth, Sv[MAX_N], totv; 
int main () { 
    N = gi(); 
    for (int i = 1; i <= N; i++) t[i] = (Node){gi(), gi(), i}; 
    for (int i = 1; i <= N; i++) Sh[++toth] = t[i].h;
    sort(&Sh[1], &Sh[toth + 1]); toth = unique(&Sh[1], &Sh[toth + 1]) - Sh - 1; 
    for (int i = 1; i <= N; i++) t[i].h = lower_bound(&Sh[1], &Sh[toth + 1], t[i].h) - Sh;
    for (int i = 1; i <= N; i++) Sv[++totv] = t[i].v;
    sort(&Sv[1], &Sv[totv + 1]); totv = unique(&Sv[1], &Sv[totv + 1]) - Sv - 1;
    for (int i = 1; i <= N; i++) t[i].v = lower_bound(&Sv[1], &Sv[totv + 1], t[i].v) - Sv; 
    for (int i = 1; i <= N; i++) f[0][i] = f[1][i] = g[0][i] = g[1][i] = 1; 
    Div(1, N, 0); reverse(&t[1], &t[N + 1]); 
    for (int i = 1; i <= N; i++) t[i].v = N + 1 - t[i].v, t[i].h = N + 1 - t[i].h; 
    Div(1, N, 1); 
    int ans = 0; double ss = 0; 
    for (int i = 1; i <= N; i++) ans = max(ans, f[0][i]); 
    for (int i = 1; i <= N; i++) if (f[0][i] == ans) ss += g[0][i]; 
    printf("%d\n", ans); 
    for (int i = 1; i <= N; i++) 
        if (f[0][i] + f[1][i] - 1 != ans) printf("0.000000 "); 
        else printf("%0.6lf ", g[0][i] * g[1][i] / ss); 
    printf("\n"); 
    return 0; 
} 

猜你喜欢

转载自www.cnblogs.com/heyujun/p/10122127.html