题目链接:https://www.nowcoder.com/acm/contest/143/F
空间限制: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; }