1. 程式人生 > >牛客多校第五場 F - take (樹狀陣列)

牛客多校第五場 F - take (樹狀陣列)

題目連結

初始的時候手裡有大小為0的鑽石,現在依次開啟n個箱子,第i個箱子有x/100的概率開出大小為y的鑽石。如果開出的鑽石比手中的要大,就交換一次。求交換次數的期望。

考慮要在某個位置交換,就必須滿足在它前面的比它大的鑽石都沒有被開出來。

也就是,第i個位置對答案的貢獻是p_{i}*\prod _{j<i,d_{j}>d_{i}}(1-p_{j})

對於這個東西,我們可以將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;
}