zoukankan      html  css  js  c++  java
  • luoguP3600 随机数生成器 期望概率DP + DP优化

    这篇题解更像对他人题解的吐槽和补充?

    考虑答案

    $E[X] = sumlimits_{i = 1}^{x} i P(X = i)$

    $P(X = i)$不好求................(其实完全可以求的......而且求法和下面的方法蜜汁相似......)

    那么,我们考虑整数概率公式(既然$P(X = i)$能求,那这公式到底有什么用?)

    $E[X] = sumlimits_{i = 1}^{x} P(x geq i)$

    当然,你也可以选择求$E[X] = sumlimits_{i = 1}^{x} i * (P(x geq i) - P(x geq i + 1))$

    或者求$E[X] = sumlimits_{i = 1}^{x} i * (P(x leq i + 1) - P(x leq i))$

    不过方法没什么本质的区别..........

    那么,考虑求枚举$x$后求$P(x geq i)$,由于题目是最大值,这是“或”概率,不好求

    因此考虑“非与非”,即求反面$1 - P(x leq i - 1)$

    相信你能发现,被包含的区间的答案是无所谓的...

    因此,将区间去包含就成了随着左端点递增,右端点递增的局面

    接着,考虑一个点能让哪些区间得出正确的结果然后转移

    不妨设一个点能影响的区间为$[L[i], R[i]]$,记为$S[i]$

    令$f[i]$表示让第$i$个小于$x$,并且$1 ... R[i]$的所有询问都合法的概率

    为了方便书写,令随机出小于等于$v$的数的概率为$p$,那么$p = frac{v}{x}$

    那么,我们枚举跟$i$的区间有交的$j$,然后让$[i + 1, j - 1]$强行大于$v$转移

    (注意,需要认为存在一段$[0, 0]$的区间,并且$0$已经选择了小于等于$v$的数来辅助转移,因此开始要特判...)

    $f[i] = (p * sumlimits_{S[i] cap S[j] eq varnothing} f[j] * (1 - p)^{i - j - 1})$

    用$two - pointer$和前缀和可以优化到$O(n)$

    (只要去掉开头的$p$就是求$P(x = i)$了,但是这么做在有点没被区间覆盖时不能采用下面的算法)

    (需要单独把没有被区间覆盖的点拿出来,不让他们参与转移...毕竟$p + 1 - p = 1$,但是$1 - p eq 1$,这么写略麻烦)

    那如果有些点完全没被区间覆盖怎么办呢?

    不妨设$[l_1, r_1], [l_2, r_2]$编号为$i, j$,且有$l_1 leq r_1 < l_2 leq r_2$

    那么对于$[r_1 + 1, l_2 - 1]$中的点,令其$S = [j, i]$(没写错)

    这时,$i$能顺利地转移到$S$一次,同时把$S$和右边的第一块没有被两个区间交的部分绑在了一起转移....

    (这可以保证增加区间$[0, 0]$和区间$[n + 1, n+1]$的正确性)

    (然而出题人并没有谈,所以数据保证所有的点都被区间覆盖?)

    最后求$P(x < i)$的时候,相当于还单独存在一段$[n + 1, n + 1]$的区间,并且$n + 1$已经选择了小于$i$的数...

    可以选择加上这段区间或者最后特判下....

    复杂度$O(nx)$

    注:$luogu$最近是不是慢了....

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    using namespace std;
    
    extern inline char gc() {
        static char RR[23456], *S = RR + 23333, *T = RR + 23333;
        if(S == T) fread(RR, 1, 23333, stdin), S = RR;
        return *S ++;
    }
    inline int read() {
        int p = 0, w = 1; char c = gc();
        while(c > '9' || c < '0') { if(c == '-') w = -1; c = gc(); }
        while(c >= '0' && c <= '9') p = p * 10 + c - '0', c = gc();
        return p * w;
    }
    
    #define ri register int
    #define sid 2005
    const int mod = 666623333;
    
    int n, x, q, ans;
    int ps[sid], snp;
    int L[sid], R[sid], f[sid], inv[sid], fac[sid];
    struct seg { 
        int l, r; 
        friend bool operator < (seg a, seg b) 
        { return a.l < b.l || (a.l == b.l && a.r > b.r); }
    } s[sid];
    
    int fp(int a, int k) {
        int ret = 1;
        for( ; k; k >>= 1, a = 1ll * a * a % mod)
        if(k & 1) ret = 1ll * ret * a % mod;
        return ret;
    }
    
    int main() {
        n = read(); x = read(); q = read();
        for(ri i = 1; i <= q; i ++) {
            int l = read(), r = read();
            s[i].l = l; s[i]. r = r;
        }
        
        sort(s + 1, s + q + 1);
        for(ri i = 1; i <= q; i ++) {
            while(s[i].r <= s[ps[snp]].r) snp --;
            ps[++ snp] = i;
        }
        q = snp; for(ri i = 1; i <= q; i ++) s[i] = s[ps[i]];
    
        int fr = 1, to = 0;
        for(ri i = 1; i <= n; i ++) {
            while(to < q && s[to + 1].l <= i) to ++;
            while(fr <= to && s[fr].r < i) fr ++;
            L[i] = fr; R[i] = to;
        }
    
        for(ri v = 1; v <= x; v ++) {
            int p = 1ll * (v - 1) * fp(x, mod - 2) % mod, bp = (1 - p + mod) % mod;
            int pc = fp(bp, mod - 2), sum = 1;
            inv[0] = fac[0] = f[0] = 1;
            for(ri i = 1; i <= n; i ++) {
                inv[i] = 1ll * inv[i - 1] * pc % mod;
                fac[i] = 1ll * fac[i - 1] * bp % mod;
            }
            for(ri i = 1, j = 0; i <= n; i ++) {
                while(j < i && R[j] < L[i] - 1) ((sum -= 1ll * f[j] * inv[j] % mod) += mod) %= mod, j ++;
                f[i] = 1ll * sum * fac[i - 1] % mod * p % mod;
                (sum += 1ll * f[i] * inv[i] % mod) %= mod; 
            }
            int anp = 0;
            for(ri i = 1; i <= n; i ++)
            if(R[i] == q) (anp += 1ll * f[i] * fac[n - i] % mod) %= mod;
            (ans += (1 - anp + mod) % mod) %= mod; 
        }
        printf("%d
    ", ans);
        return 0;
    }
  • 相关阅读:
    C# Redis实战(五)
    C# Redis实战(四)
    C# Redis实战(三)
    C# Redis实战(二)
    C# Redis实战(一)
    memcached的基本命令(安装、卸载、启动、配置相关)
    git和tortoisegit安装教程
    编程规范是非常重要的,为什么说可读性比什么都重要?你有没有确定一个编程规范呢?
    关于VR游戏的前景
    在项目开发过程中如何处理人际关系
  • 原文地址:https://www.cnblogs.com/reverymoon/p/9515358.html
Copyright © 2011-2022 走看看