[2018牛客多校(第五场)] take (树状数组+概率)

题目链接

take

题目大意

一共有n个箱子, 第i 个箱子有p[i]% 的概率开出大小为d[i] 的钻石。 初始玩家手里有一个size为0的钻石, 且手里最多只能有一个钻石, 如果当前开的箱子中得到的钻石大于手中的钻石, 则替换, 问最终替换次数的期望是多少。 最终对答案模998244353。

数据范围

1n105
1p[i]100
1d[i]109

解题思路

题意是让求交换钻石次数的期望, 因为根据期望的性质E(x+y)=E(x)+E(y) , 可以将问题转换为每个钻石对次数期望的贡献, 因为每个钻石最多只能交换一次, 所以每个钻石的贡献就是这个钻石被选中的概率 × 这个钻石能贡献的交换次数(1次), 也就是求每个钻石被选中的概率和。
如果第i 个钻石要被选中, 那么前i1size 比他大的都不能出现, 其他小的无所谓, 所以对于第i 个钻石对答案的贡献就是p[i]×(j<i,d[j]>d[i])(100p[j]) .

所以每次需要求一个前缀乘积, 可以用树状数组或者线段树解决。
因为是维护乘积, 所以要将树状数组初始化为1, 同时还需要考虑维护分数用逆元处理一下。

使用树状数组按照size大小从大到小排序, 那么每次查询的树状数组的前缀乘积都是比他大的数的乘积。

/********************************************
 *Author*        :ZZZZone
 *Created Time*  : 日  8/ 5 17:08:31 2018
 * Ended  Time*  : 日  8/ 5 17:28:23 2018
*********************************************/

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <string>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <stack>
using namespace std;
#define debug(x) std::cerr << #x << " = " << (x) << std::endl
typedef pair<int, int> PII;
typedef long long LL;
typedef unsigned long long ULL;

inline void OPEN(string s){
    freopen((s + ".in").c_str(), "r", stdin);
    freopen((s + ".out").c_str(), "w", stdout);
}

const int MAXN = 1e5;
const int Mod = 998244353;

struct Node{
    int p, sz, id;
    bool operator < (const Node& tmp) const{
        return sz > tmp.sz || (sz == tmp.sz && id < tmp.id);
    }
}a[MAXN+5];

LL bitsum[MAXN+5];
int n;

LL fast_pow(LL x, LL y){
    LL res = 1LL;
    while(y != 0){
        if(y & 1) res =(res * x) % Mod;
        y >>= 1;
        x = (x * x) % Mod;
    }
    return res;
}

inline int lowbit(int x){return (x & (-x)); }

inline void Add(int p, LL x){
    while(p <= n){
        bitsum[p] = (bitsum[p] * x) % Mod;
        p += lowbit(p);
    }
}

inline LL Sigma(LL p){
    LL res = 1LL;
    while(p){
        res = (res * bitsum[p]) % Mod;
        p -= lowbit(p);
    }
    return res;
}

void Init(){
    scanf("%d", &n);
    for(int i = 1; i <= n; i++){
        scanf("%d %d", &a[i].p, &a[i].sz);
        a[i].id = i;
    }
    sort(a + 1, a + 1 + n);
    for(int i = 0; i <= MAXN; i++) bitsum[i] = 1LL;
}

void Solve(){
    LL ans = 0LL ,inv = fast_pow(100LL, Mod - 2);
    for(int i = 1; i <= n; i++){
        LL tmp = Sigma(a[i].id-1) * (LL)a[i].p % Mod * inv % Mod;
        ans = (ans + tmp) % Mod;
        Add(a[i].id, inv * (100LL - (LL)a[i].p) % Mod);
    }
    printf("%lld\n", ans);
}

int main()
{
    Init();
    Solve();
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章