牛客网暑期ACM多校训练营(第五场)F take(概率, 递推)

链接:

https://www.nowcoder.com/discuss/84119

题意:

给定n个箱子, 每个箱子打开发现钻石的概率P(这里的P要除100), 每个钻石的重量, 有一个人只能持有一个钻石, 每次打开箱子发现手中的钻石小于箱子的钻石, 他就会换掉手中的钻石, 求交换次数的数学期望

分析:

对于一个箱子, 取里面钻石的概率就是(P * (之前不打开比它重的概率)), 那么从最重的钻石开始递推, 用树状数组统计(之前不打开)的概率, 然后把这个点设为不打开。

树状数组一开始初始化为1, 这些箱子起始不打开的概率为1.

#include<bits/stdc++.h>
using namespace std;
const int MOD = 998244353;
const int maxN = 1e6 + 7;
int n;
long long c[maxN];
struct box{
    long long p, d, index;
    bool operator < (const box& a) const{
        return d != a.d ? d > a.d : index < a.index;
    }
}a[maxN];
long long inv(long long a, long long m){
    if(a == 1) return 1;
    return inv(m % a, m) * (m - m / a) % m;
}
int lowbit(int x){
    return x & -x;
}
long long sum(int x){
    long long ret = 1;
    while(x > 0){
        ret *= c[x];
        ret %= MOD;
        x -= lowbit(x);
    }
    return ret;
}
void update(int x, int val){
    while(x <= n){
        c[x] *= val;
        c[x] %= MOD;
        x += lowbit(x);
    }
}
int main(){
//    freopen("1.txt","r", stdin);
//    freopen("123.txt","w", stdout);
    long long INV = inv(100, MOD);
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        c[i - 1] = 1;
        scanf("%lld %lld", &a[i].p, &a[i].d);
        a[i].index = i;
    }
    sort(a + 1, a + n + 1);
    long long ans = 0;
    long long temp = 0;
    for(int i = 1; i <= n; i++){
        long long p = a[i].p, id = a[i].index;
        temp = ((( p * sum(id-1) ) % MOD ) * INV) % MOD; //前面不取得概率之积 * 该点的概率
//        printf("%lld %lld\n",sum(id - 1),  temp);
        ans = (ans + temp) % MOD;
        update(id, (100 - p) * INV % MOD); //把该点更新成不取的
    }
    printf("%lld\n", ans);
    return 0;
}

 

posted @ 2018-08-07 15:47  Neord  阅读(156)  评论(0编辑  收藏  举报