牛客多校第五場 F - take (樹狀陣列)
阿新 • • 發佈:2018-11-10
初始的時候手裡有大小為0的鑽石,現在依次開啟n個箱子,第i個箱子有x/100的概率開出大小為y的鑽石。如果開出的鑽石比手中的要大,就交換一次。求交換次數的期望。
考慮要在某個位置交換,就必須滿足在它前面的比它大的鑽石都沒有被開出來。
也就是,第i個位置對答案的貢獻是。
對於這個東西,我們可以將d從大到小排序,用樹狀陣列去維護(1-pi)的字首積。依次加入到樹狀陣列中時,由於加入的肯定是比當前的鑽石更大的,所以只需要查詢一波字首積就可以更新答案。
相應的,考慮到d的範圍,需要進行離散化。
#include <cstdio> #include <cstring> #include <queue> #include <vector> #include <iostream> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 100050; const ll INF = (1LL << 62) - 1; const ll mod = 998244353; int n; ll tree[maxn], d[maxn]; int lowbit(int x) {return x & (-x);} struct node { ll p, d; }e[maxn]; ll qpow(ll a, ll x) { ll res = 1; while(x) { if(x & 1) res = (res*a) % mod; a = (a*a) % mod; x >>= 1; } return res; } ll query(int x) { ll res = 1; while(x <= n) { res = (res*tree[x]) % mod; x += lowbit(x); } return res; } void update(int x, ll d) { while(x > 0) { tree[x] = (tree[x]*d) % mod; x -= lowbit(x); } } int main() { scanf("%d", &n); for(int i = 1;i <= n;i++) { scanf("%lld%lld", &e[i].p, &e[i].d); d[i-1] = e[i].d; } ll inv = qpow(100, mod - 2); sort(d, d+n); int cnt = unique(d, d+n) - d; for(int i = 1;i <= n;i++) { tree[i] = 1; e[i].d = lower_bound(d, d+cnt, e[i].d) - d + 1; } ll ans = 0; for(int i = 1;i <= n;i++) { ans = (ans + query(e[i].d)*e[i].p%mod*inv%mod) % mod; update(e[i].d, 1LL*(100 - e[i].p)*inv%mod); } printf("%lld\n", ans); return 0; }