初始的时候手里有大小为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;
}