2018牛客网暑期ACM多校训练营(第五场) F

题目链接:https://www.nowcoder.com/acm/contest/143/F

时间限制:C/C++ 1秒,其他语言2秒
空间限制:C/C++ 262144K,其他语言524288K
64bit IO Format: %lld

题目描述

Kanade has n boxes , the i-th box has p[i] probability to have an diamond of d[i] size.

At the beginning , Kanade has a diamond of 0 size. She will open the boxes from 1-st to n-th. When she open a box,if there is a diamond in it and it's bigger than the diamond of her , she will replace it with her diamond.

Now you need to calculate the expect number of replacements.

You only need to output the answer module 998244353.

Notice: If x%998244353=y*d %998244353 ,then we denote that x/y%998244353 =d%998244353

输入描述:

The first line has one integer n.

Then there are n lines. each line has two integers p[i]*100 and d[i].

输出描述:

Output the answer module 998244353

输入

3
50 1
50 2
50 3

输出

499122178

备注:

1<= n <= 100000

1<=p[i]*100 <=100

1<=d[i]<=10^9

题意:

有n个盒子,每个盒子里有p[i]的概率有一颗d[i]大小的钻石,Kanade现在手上有一颗0大小的钻石,他遇到比手上大的钻石就会进行交换,

现在Kanade从1~n打开盒子,计算交换次数的期望。

Notice:

If x%998244353=y*d %998244353 ,then we denote that x/y%998244353 =d%998244353

这句话提示我们如何用整数表示小数,我们定 (p/100)%998244353 = d%998244353,这个d满足 (100*d)%998244353 = p%998244353,

这个整数d,就相当于p/100。

题解:

对于第 i 个盒子,选取这颗钻石进行交换的概率是:前面 1 ~ i-1 颗钻石中比这颗大的那些,都没有出现的概率,乘上当前这颗钻石出现的概率,

即 $pleft[ i ight]prodlimits_{j < i,dleft[ i ight] < dleft[ j ight]} {left( {1 - pleft[ j ight]} ight)}$,

而交换次数的期望,就等于求和:“每个盒子交换的概率乘以交换1次(数值上就等于概率)”。

但是不可能 $Oleft( {n^2 } ight)$ 过,所以考虑前缀优化,我们可以用树状数组维护原序列的前缀积,

再把盒子按 $dleft[ i ight]$ 降序排序,然后进行枚举,

此时,对于第 i 个盒子,比体积它大的都已经计算过了,都存在树状数组里了,就可以直接查询。

(参考:https://www.nowcoder.com/discuss/89992?type=101&order=0&pos=1&page=0

AC代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=100000+10;
const ll MOD=998244353;

int n;
struct Box{
    ll p,d;
    int id;
}box[maxn];
bool cmp(Box a,Box b)
{
    if(a.d==b.d) return a.id<b.id;
    return a.d>b.d;
}

struct _BIT //单点增加,区间查询
{
    int n;
    ll C[maxn];
    int lowbit(int x){return x&(-x);}
    void init(int n)
    {
        this->n=n;
        for(int i=1;i<=n;i++) C[i]=1;
    }
    void add(int pos,ll val) //在pos点乘上val
    {
        while(pos<=n)
        {
            C[pos]=C[pos]*val%MOD;
            pos+=lowbit(pos);
        }
    }
    ll ask(int pos) //查询1~pos点的积
    {
        ll ret=1;
        while(pos>0)
        {
            ret=ret*C[pos]%MOD;
            pos-=lowbit(pos);
        }
        return ret;
    }
}BIT;

ll pow(ll a,ll b) //快速幂
{
    ll r=1,base=a%MOD;
    while(b){
        if(b&1) r*=base , r%=MOD;
        base*=base;
        base%=MOD;
        b>>=1;
    }
    return r;
}
ll inv(ll a){return pow(a,MOD-2);} //求逆元

int main()
{
    cin>>n;
    BIT.init(n);
    for(int i=1;i<=n;i++)
    {
        cin>>box[i].p>>box[i].d;
        box[i].id=i;
    }
    sort(box+1,box+n+1,cmp);

    ll inv100=inv(100);
    ll ans=0;
    for(int i=1;i<=n;i++)
    {
        ans+=(box[i].p*inv100)%MOD * BIT.ask(box[i].id-1)%MOD;
        ans%=MOD;
        BIT.add(box[i].id,(100-box[i].p)*inv100%MOD);
    }
    cout<<ans<<endl;
}
原文地址:https://www.cnblogs.com/dilthey/p/9420747.html