题目:有n个盒子,每一个盒子i有p[i]的概率开出d[i]大的钻石,现在持大小为0的钻石,依次从1~n打开箱子,如果箱子内的钻石比手中的大时就交换。求交换次数的期望。
思路:交换的前提是其前面比这个大的钻石都没打开,当前这个开出了钻石,所以可以先从大的钻石考虑,用树状数组维护一下大钻石造成的影响。题目给的输入输出格式中间计算要用逆元。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const ll mod=998244353;
ll qmod(ll x,ll p)
{
ll ans=1;
while(p)
{
if(p&1) ans=ans*x%mod;
x=x*x%mod;
p>>=1ll;
}
return ans;
}
struct node{
ll p,d;
int id;
}a[maxn];
bool cmp(const node &a,const node &b)
{
return a.d>b.d;
}
ll c[maxn];
int n;
int lowbit(int x) {return x&-x;}
void update(int pos,ll val)
{
while(pos<=n)
{
c[pos]=c[pos]*val%mod;
pos+=lowbit(pos);
}
}
ll query(int pos)
{
ll ans=1;
while(pos>0)
{
ans=ans*c[pos]%mod;
pos-=lowbit(pos);
}
return ans;
}
int main()
{
ll _100=qmod(100ll,mod-2);
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].p,&a[i].d);
a[i].id=i;
}
sort(a+1,a+n+1,cmp);
for(int i=0;i<=n;i++)
c[i]=1ll;
ll ans=0;
for(int i=1;i<=n;i++)
{
ll tmp=a[i].p*_100%mod*query(a[i].id-1)%mod;//当前开出钻石的概率*前面比它没开出钻石的概率累积
ans=(ans+tmp)%mod;
update(a[i].id,(100ll-a[i].p)*_100%mod);//更新(1-p)
}
printf("%lld\n",ans);
return 0;
}