NowCoder2018多校F Take 期望 转化
NowCoder2018多校F Take 期望 转化
题意
给出\(n\)个物品,对于第\(i\)个物品,有\(p_i\)的概率打开这个物品,若该物品的权值\(d[i]\)比当前获得的物品的最大值大,就更新这个最大值
求更新的期望次数
\[1\leq n \leq 100000\\
1 \leq p_i \leq 100\\
1\leq d_i \leq 1e9
\]
分析
直接做显然是一个复杂度较高的二维DP
考虑计算每个物品对总更新次数的贡献,每个物品能够被作为最大值更新显然和后面的东西没有关系,前面的物品权值小于等于它的和它也没更新(打不打开都是1),因此只需要管前\(i - 1\)个物品中权值大于\(d_i\)的物品
有
\[E= P = p_i \prod_{j <i \and d_j > d_i} (1-p_j)
\]
显然树状数组扫一遍或者线段树维护后缀积即可
代码
const int maxn = 1e5 + 5;
inline int get(VI &a,int val){
return lower_bound(all(a),val) - a.begin();
}
struct BIT{
int c[maxn<<2];
void init() {
fill(c,c+(maxn<<2),1);
}
void add(int p, int x, int l, int r, int i) {
if (p == l && p == r) {
c[i] = mul(c[i], x);
return;
}
int mid = l + r >> 1;
if (p <= mid) add(p, x, l, mid, i << 1);
else add(p, x, mid + 1, r, i << 1 | 1);
c[i] = mul(c[i << 1], c[i << 1 | 1]);
}
void ADD(int pos,int x){
add(pos, x, 1, maxn, 1);
}
int qr(int l, int r, int L, int R, int i) {
if (l <= L && r >= R) {
return c[i];
}
int mid = L + R >> 1;
int res = 1;
if (l <= mid) res = mul(res, qr(l, r, L, mid, i << 1));
if (r > mid) res = mul(res, qr(l, r, mid + 1, R, i << 1 | 1));
return res;
}
int query(int pos){
return qr(pos, maxn, 1, maxn, 1);
}
}bit;
int main(){
int iv = ksm(100);
int n = rd();
int MUL = 1;
VI p(n + 1),d(n + 1);
for(int i = 1;i <= n;i++)
p[i] = rd(),d[i] = rd();
int ans = 0;
auto a = d;
sort(all(a));
a.erase(unique(all(a)),a.end());
int len = (int)a.size();
bit.init();
// for(int i = 1;i <= len;i++)
// bit.c[i] = 1;
for(int i = 1;i <= n;i++){
int tmp = mul(p[i],iv);
int val = get(a,d[i]);
//tmp = mul(tmp,mul(MUL,ksm(bit.query(val))));
tmp = mul(tmp, bit.query(val + 1));
add(ans,tmp);
// int v = mul(bit.query(val),ksm(bit.query(val - 1)));
// bit.ADD(val,ksm(v));
// bit.ADD(val,mul(100 - p[i],iv));
// MUL = mul(MUL,mul(100 - p[i],iv));
bit.ADD(val, mul(100-p[i], iv));
}
cout << ans;
}