【LG2481】[SDOI2011]攔截導彈
阿新 • • 發佈:2018-12-14
【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; }