牛客网多校5 F.take (树状数组)

题目:有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;
}

猜你喜欢

转载自blog.csdn.net/dllpXFire/article/details/81388516