版权声明:本文为博主原创文章,禁止所有形式的未经博主允许的转载行为。 https://blog.csdn.net/qq_33330876/article/details/81392311
题目大意
有 n 个箱子,每打开一个箱子有 pi 的概率出现一个大小为 di 的钻石。以 1~n 的顺序打开箱子,每开到比手里的钻石更大的钻石就把手里的钻石换掉,求期望交换次数。
https://www.nowcoder.com/acm/contest/143/F
解题思路
基于期望的线性性,分别求出第 i 个箱子的钻石被交换的概率 p = p(第 i 个箱子前面的所有钻石尺寸大于等于第 i 个箱子中钻石尺寸的箱子均未被打开)× p(第 i 个箱子被打开)。
我们以钻石尺寸从大到小为第一关键字,钻石位置从小到大为第二关键字对箱子排序。之后即可用树状数组维护前缀积,也就是 p(第 i 个箱子前面的所有钻石尺寸大于等于第 i 个箱子中钻石尺寸的箱子均未被打开的概率)。
困扰了学长好久,不过想得清晰一点还是比较好写的。
代码
#include <bits/stdc++.h>
using namespace std;
inline int read() {
register int val=0, sign=1; char ch;
while(~(ch=getchar()) && (ch<'0' || ch>'9') && ch!='-'); ch=='-'?sign=-1:val=ch-'0';
while(~(ch=getchar()) && (ch>='0' && ch<='9')) val=(val<<1)+(val<<3)+ch-'0';
return val*sign;
}
#define mp make_pair
#define x first
#define y second
#define lowbit(k) ((k)&(-(k)))
const int maxn=int(1e5)+111, moder=998244353, inv100=828542813;
typedef pair<int,int> pii;
inline int mul(const int &a,const int &b) {return 1ll*a*b%moder;}
inline int add(const int &a,const int &b) {return (a+b<moder)?a+b:a+b-moder;}
bool cmp(const pii &a,const pii &b) {if(a.x==b.x) return a.y<b.y; else return a.x>b.x;}
int n;
int p[maxn], d[maxn];
pii cp[maxn];
int pro[maxn];
void modify(int pos,int v) {
for(;pos<=n;pro[pos]=mul(pro[pos],v),pos+=lowbit(pos));
return;
}
int query(int pos) {
int res=1;
for(;pos;res=mul(res,pro[pos]),pos-=lowbit(pos));
return res;
}
void work() {
n=read();
register int i;
for(i=1;i<=n;++i) {
p[i]=read(), d[i]=read();
pro[i]=1;
cp[i]=mp(d[i],i);
}
sort(cp+1,cp+1+n,cmp);
int ans=0;
for(i=1;i<=n;++i) {
int id=cp[i].y, val=query(id);
ans=add(ans,mul(val,mul(p[id],inv100)));
modify(id,mul(100-p[id],inv100));
}
printf("%d\n",ans);
return;
}
int main() {
#ifndef ONLINE_JUDGE
freopen("input.txt","r",stdin);
#endif
work();
return 0;
}