Solved:3
rank:195
F. take
官方题解:小 A 在打开第 i 个箱子后会交换手中的钻石和第 i 个箱子中的钻石
当且仅当第 i个箱子的钻石是前 i 个箱子打开后出现的所有钻石里最大的。
那么要算概率的话,前面箱子中钻石大于等于它的打开后就不能有钻石
用树状数组维护一下
线段树(不会树状数组) 调了半天居然快速幂忘记写返回了
#include <stdio.h> #include <algorithm> #include <iostream> #include <string.h> using namespace std; typedef long long ll; const ll mod = 998244353; ll sum[400005]; int num[100005]; ll pow_mod(ll x, ll y) { ll res = 1; while(y) { if(y & 1) res = res * x % mod; y >>= 1; x = x * x % mod; } return res; } struct node { int p, d, id; }E[100005]; bool cmp1(node A, node B) { return A.d < B.d; } bool cmp2(node A, node B) { return A.id < B.id; } void pushup(int rt) { sum[rt] = sum[rt << 1] * sum[rt << 1 | 1] % mod; } void build(int l, int r, int rt) { if(l == r) { sum[rt] = 1; return; } int m = l + r >> 1; build(l, m, rt << 1); build(m + 1, r , rt << 1 | 1); pushup(rt); } void update(int k, ll v, int l, int r, int rt) { if(l == r) { sum[rt] = v; return; } int m = l + r >> 1; if(k <= m) update(k, v, l, m, rt << 1); else update(k, v, m + 1, r, rt << 1 | 1); pushup(rt); } ll query(int ql, int qr, int l, int r, int rt) { if(ql <= l && qr >= r) return sum[rt]; ll res = 1; int m = l + r >> 1; if(ql <= m) res = res * query(ql, qr, l, m, rt << 1) % mod; if(qr > m) res = res * query(ql, qr, m + 1, r, rt << 1 | 1) % mod; return res; } int main() { int n; scanf("%d", &n); ll ny = pow_mod(100, mod - 2); for(int i = 1; i <= n; i++) { scanf("%d%d", &E[i].p, &E[i].d); E[i].id = i; E[i].p = 100 - E[i].p; } sort(E + 1, E + 1 + n, cmp1); for(int i = 1; i <= n; i++) num[E[i].id] = i; sort(E + 1, E + 1 + n, cmp2); build(1, n, 1); ll ans = 0; for(int i = 1; i <= n; i++) { int v = num[E[i].id]; ans = (ans + query(v, n, 1, n, 1) * (100 - E[i].p) % mod * ny % mod) % mod; update(v, E[i].p * ny % mod, 1, n, 1); } printf("%lld\n", ans); return 0; }