zoukankan      html  css  js  c++  java
  • 《期望与概率练习》

    写着写着拿出了我的概率论书(哭

    连续性随机变量X的期望:$E[X] = sum_{x = -INF}^{INF} x * f(x) dx $ - f(x)为概率密度.

    https://www.luogu.com.cn/problem/P4316:

    一开始写了个暴力,结果过了?可能DAG不太好卡暴力吧。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,double> pii2;
    const int N = 1e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 1e9 + 7;
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    vector<pii> G[N];
    vector<pii2> vec[N];
    int in[N];
    void solve() { 
        int n,m;scanf("%d %d",&n,&m);
        while(m--) {
            int u,v,w;scanf("%d %d %d",&u,&v,&w);
            G[u].push_back(pii{v,w});
            in[v]++;
        }
        queue<int> Q;
        Q.push(1);
        vec[1].push_back(pii2{0,1});
        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();
            double p = 1.0 / G[u].size();
            for(auto v : G[u]) {
                in[v.first]--;
                for(auto tt : vec[u]) {
                    vec[v.first].push_back(pii2{tt.first + v.second,tt.second * p});
                }
                if(in[v.first] == 0) Q.push(v.first);
            }
        }
        double ans = 0;
        for(auto v : vec[n]) ans += v.first * v.second;
        printf("%.2f
    ",ans);
    }   
    int main() {
        solve();
        //system("pause");
        return 0;
    }
    View Code

    正解:考虑期望dp。

    因为是从1 -> n,所以可以定义dp[i] = i走到n的期望路径长度。

    那么显然可以有dp[n] = 0,所以很显然我们要逆推,所以要建反图。

    $dp[u] = sum (dp[v] + w[u -> v]) * p$需要注意的是这里的p应该是v到u的概率,因为虽然我们是逆推的,但是实际上我们是正着走的。

    然后也不难理解,如果转移成功能获得的贡献是$dp[v] + w[u -> v]$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,double> pii2;
    const int N = 1e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 1e9 + 7;
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    vector<pii> G[N];
    int in[N],sz[N];
    double dp[N];
    void solve() { 
        int n,m;scanf("%d %d",&n,&m);
        while(m--) {
            int u,v,w;scanf("%d %d %d",&u,&v,&w);
            G[v].push_back(pii{u,w});
            in[u]++,sz[u]++;
        }
        queue<int> Q;
        Q.push(n);
        dp[n] = 0;
        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();
            for(auto v : G[u]) {
                in[v.first]--;
                dp[v.first] +=  (dp[u] + v.second) * (1.0 / sz[v.first]);
                if(in[v.first] == 0) Q.push(v.first);
            }
        }
        printf("%.2f
    ",dp[1]);
    }   
    int main() {
        solve();
        //system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P5104:

    这么大的数据只能基于矩阵快速幂去考虑,但是由于这里是对于连续形状随机变量而言,也不好dp。

    我们首先可以计算第一个取的人的期望钱数.$E1 = sum_{x = 0}^{w} x frac{1}{w} dx = frac{1}{2} w$

    因为E1 = w / 2,所以w - E1 = E1

    我们继续第二个人的期望钱数$E2 = sum_{x = 0}^{E1} x frac{1}{E1} dx = frac{1}{2} E1$

    由此可见后面的递推都是1 / 2,那么可得第k个人的期望钱数 = w / 2 ^ k

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,double> pii2;
    const int N = 1e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 1e9 + 7;
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = re * a % Mod;
            a = a * a % Mod;
            b >>= 1;
        }
        return re;
    }
    void solve() { 
        LL w,n,k;scanf("%lld %lld %lld",&w,&n,&k);
        LL ma = quick_mi(2,k);
        LL ans = MUL(w,quick_mi(ma,Mod - 2));
        printf("%lld
    ",ans);
    
    }   
    int main() {
        solve();
        system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P6154:

    $DAG上的随机游走:考虑每条边的贡献即可。$

    $对于一条边u -> v,经过这条边的路径数cnt = 原图拓扑到u的次数 * 反图拓扑到v的次数$

    $然后每条路径的期望就是 1 * (cnt / sum)$

    $这个sum我们只需要第一遍拓扑的时候处理出来即可$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,double> pii2;
    const int N = 1e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = re * a % Mod;
            a = a * a % Mod;
            b >>= 1;
        }
        return re;
    }
    LL dp[N],dp2[N],sum = 0;
    int in[N],de[N];
    vector<int> G[N],RG[N];
    void solve() { 
        int n,m;scanf("%d %d",&n,&m);
        while(m--) {
            int x,y;scanf("%d %d",&x,&y);
            G[x].push_back(y);
            RG[y].push_back(x);
            in[y]++,de[x]++;
        }
        queue<int> Q;
        for(int i = 1;i <= n;++i) {
            dp2[i] = 1;
            if(de[i] == 0) Q.push(i);
        }
        while(!Q.empty()) {
            int u = Q.front();
            sum = ADD(sum,dp2[u]);
            Q.pop();
            for(auto v : RG[u]) {
                dp2[v] = ADD(dp2[v],dp2[u]);
                de[v]--;
                if(de[v] == 0) Q.push(v);
            }
        }
        for(int i = 1;i <= n;++i) {
            dp[i] = 1;
            if(in[i] == 0) Q.push(i);
        }
        LL ans = 0;
        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();
            for(auto v : G[u]) {
                ans = ADD(ans,MUL(MUL(dp[u],dp2[v]),quick_mi(sum,Mod - 2)));
                dp[v] = ADD(dp[v],dp[u]);
                in[v]--;
                if(in[v] == 0) Q.push(v);
            }
        }
        printf("%lld
    ",ans);
    }   
    int main() {
        solve();
        system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P1297:

    $不知道为什么这题感觉还是有些难度的,但是我一看到就想到了做法$

    $dp[i]表示做了i道题的期望做对题数,递推式:dp[i] = dp[i - 1] + min(a[i],a[i + 1]) / (a[i] * a[i + 1])$

    $并不是很难想,相邻的一共答案对应情况有a[i] * a[i + 1]种,并且其中正确的只有min(a[i],a[i + 1])种$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    typedef pair<LL,double> pii2;
    const int N = 1e7 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int n,A,B,C,a[N];
    void Input() {
        scanf("%d%d%d%d%d", &n, &A, &B, &C, a + 1);
        for (int i = 2; i <= n; i++)
            a[i] = ((long long) a[i - 1] * A + B) % 100000001;
        for (int i = 1; i <= n; i++)
            a[i] = a[i] % C + 1;
    }
    double dp[N];//做了i道题的期望做对题数
    void solve() { 
        Input();
        for(int i = 1;i <= n;++i) {
            if(i == n) {
                dp[i] = dp[i - 1] + 1.0 * min(a[i],a[1]) / (1LL * a[i] * a[1]);
            }   
            else {
                dp[i] = dp[i - 1] + 1.0 * min(a[i],a[i + 1]) / (1LL * a[i] * a[i + 1]);
            }
        }
        printf("%.3f
    ",dp[n]);
    
    }   
    int main() {
        solve();
        system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P1291:

    $这里就写一下思路了,因为输出太毒瘤了就不写了$
    $很显然有一个dp[i] - 抽到i个不同球星的期望次数$

    $定义dp[i + 1] = dp[i] + x$

    $那么我们可以有第二种转移方式dp[i + 1] = dp[i] + 1 * (n - i / n) + (x + 1) * (i / n)$

    $可以由x = 1 * (n - i / n) + (x + 1) * (i / n),解得 x =  n / (n - i),所以可得dp[i + 1] = dp[i] + n / (n - i)$

    https://www.luogu.com.cn/problem/CF1042E:

    $虽然这里看起来是个矩阵图,但是大的往小的连边后,其实就是一个有起点的DAG游走$

    $但是这里如果真的要连边那么复杂度吃不消,因为这里它一定会向小的连边,所以我们可以对所有点的权值排序$

    $那么就类似一条x坐标轴,显然有dp[i] - 到i点的期望分数。但是这个题如果要正向推,那么化简就会比较麻烦,所以我们考虑逆推$

    $dp[i]表示到所有终点的期望分数。那么有 dp[i] = sum_{a[j] > a[i]}^{} dp[j] + (xi - xj) ^ 2 + (yi - yj) ^ 2$

    $里面拆开后可以前缀和优化,就卡在这里化简老是不对..$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1e3 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int a[N][N];
    LL dp[N * N];//走到第i个点的期望分数
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = re * a % Mod;
            a = a * a % Mod;
            b >>= 1;
        }
        return re;
    }
    struct Node{LL x,y,z;};
    vector<Node> vec;
    bool cmp(Node a,Node b) {
        return a.z < b.z;
    }
    LL f[N * N];
    LL num,numx,numy,numx2,numy2;
    LL nownum,nownumx,nownumy,nownumx2,nownumy2;
    LL sumf,nowsumf;
    void solve() { 
        int n,m;scanf("%d %d",&n,&m);
        for(int i = 1;i <= n;++i)
            for(int j = 1;j <= m;++j) scanf("%d",&a[i][j]);
        int x,y;scanf("%d %d",&x,&y);
        int mi = INF;
        for(int i = 1;i <= n;++i) {
            for(int j = 1;j <= m;++j) {
                if(a[i][j] < a[x][y]) vec.push_back(Node{i,j,a[i][j]}),mi = min(mi,a[i][j]);
            }
        }
        vec.push_back(Node{x,y,a[x][y]});
        sort(vec.begin(),vec.end(),cmp);
        n = vec.size();
        for(int i = 1;i <= n;++i) {
            f[i] = quick_mi(i,Mod - 2);//1 / i
        }
        for(int i=1;i<=n;i++){
            if(i == 1 || vec[i - 1].z != vec[i - 2].z){
                num+=nownum;numx+=nownumx;numy+=nownumy;
                numx2+=nownumx2;numy2+=nownumy2;
                nownum=nownumx=nownumy=nownumx2=nownumy2=0;
                sumf+=nowsumf;nowsumf = 0;
            }
            dp[i] = (num * (vec[i - 1].x * vec[i - 1].x + vec[i - 1].y * vec[i - 1].y) % Mod + numx2 + numy2 -2 * vec[i - 1].x*numx%Mod-2*vec[i - 1].y*numy%Mod+sumf)%Mod*f[num]%Mod;
            nownum++;
            nownumx += vec[i - 1].x;nownumy += vec[i - 1].y;
            nownumx2 += vec[i - 1].x * vec[i - 1].x;
            nownumy2 += vec[i - 1].y * vec[i - 1].y;
            nowsumf += dp[i];
            nownumx %= Mod;
            nownumy %= Mod;
            nownumx2 %= Mod;
            nownumy2 %= Mod;
            nowsumf %= Mod;
        }
        printf("%lld
    ",dp[n]);
    
    }   
    int main() {
        solve();
        //system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P1850:

    $这题其实非常不错,很显然有dp[i][j][k] - 到第i个申请了j次,k 0/1 - 前面一个有没有申请.$

    $这里的转移瓶颈就在于前面一个如果申请了,那么我们就不知道它会在哪里,因为有可能失败。$

    $这里其实我们只需要把申请成功的代价 和 申请失败的 都加上就好了,并不需要去真正关心它的前面一个位置。$

    $这里需要注意的是概率需要满足两个如果两个都申请了,那就是乘法原则计算概率。$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 2e3 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int n,m,v,e,c[N],d[N];
    double k[N];
    int dis[305][305];
    double dp[N][N][2];//dp[i][j][k] - 到i个时间段,申请了j个的最小期望体力花费,k - 0这一次没有申请,1 - 申请了
    void Floyd() {
        for(int kk = 1;kk <= v;++kk) {
            for(int i = 1;i <= v;++i) {
                for(int j = 1;j <= v;++j) {
                    dis[i][j] = min(dis[i][j],dis[i][kk] + dis[kk][j]);
                }
            }
        }
    }
    void solve() { 
        scanf("%d %d %d %d",&n,&m,&v,&e);
        for(int i = 1;i <= n;++i) scanf("%d",&c[i]);
        for(int i = 1;i <= n;++i) scanf("%d",&d[i]);
        for(int i = 1;i <= n;++i) cin >> k[i];
        memset(dis,0x3f3f3f,sizeof(dis));
        for(int i = 1;i <= v;++i) dis[i][i] = 0;
        while(e--) {
            int u,v,w;scanf("%d %d %d",&u,&v,&w);
            dis[v][u] = dis[u][v] = min(dis[u][v],w);
        }
        Floyd();
        for(int i = 0;i <= n;++i) 
            for(int j = 0;j <= m;++j) 
                for(int k = 0;k < 2;++k) dp[i][j][k] = INF;
        double ans = INF;
        dp[1][0][0] = dp[1][1][1] = 0;
        for(int i = 2;i <= n;++i) {
            for(int j = 0;j <= m;++j) {
                int d1 = dis[c[i - 1]][c[i]],d2 = dis[d[i - 1]][c[i]],d3 = dis[c[i - 1]][d[i]],d4 = dis[d[i - 1]][d[i]];
                dp[i][j][0] = min(dp[i][j][0],dp[i - 1][j][0] + d1);
                dp[i][j][0] = min(dp[i][j][0],dp[i - 1][j][1] + k[i - 1] * d2 + (1 - k[i - 1]) * d1);
                if(j > 0) {
                    dp[i][j][1] = min(dp[i][j][1],dp[i - 1][j - 1][0] + k[i] * d3 + (1 - k[i]) * d1);   
                    dp[i][j][1] = min(dp[i][j][1],dp[i - 1][j - 1][1] + k[i - 1] * k[i] * d4 +  (1 - k[i - 1]) * (1 - k[i]) * d1 + k[i - 1] * (1 - k[i]) * d2 + (1 - k[i - 1]) * k[i] * d3);
                }
                if(i == n) ans = min(ans,min(dp[i][j][0],dp[i][j][1]));
            }
        }
        if(n == 1) printf("0.00
    ");
        else printf("%.2f
    ",ans);
    
    }   
    int main() {
        solve();
       // system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P1365:

    $这题有点抽象,显然我们要计算的就是一连串?o组合的期望值。$

    $可以考虑我们目前的o长度为len,价值为len ^ 2:$

    $如果下一个为o,那么价值为(len + 1) ^ 2 - len ^ 2 = 2 * len + 1$

    $如果下一个为?,我们需要考虑为x的代价 = 0,为o的代价 = 2 * len + 1$

    $出现o的概率为1 / 2,那么我们可以获得的期望代价就是(2 * len + 1) / 2 = len + 0.5$

    $就这样处理连续一段即可,需要注意的是len 在是 ?时应该加为 (len + 1) / 2$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int n;
    double dp[N];//dp[i] - 到第i个字符的期望分数.
    void solve() { 
        scanf("%d",&n);
        string s;cin >> s;
        double len = 0;
        for(int i = 1;i <= n;++i) {
            if(s[i - 1] == 'x') dp[i] = dp[i - 1],len = 0;
            else if(s[i - 1] == 'o') {
                dp[i] = dp[i - 1] + 2 * len + 1,++len;
            }
            else {
                dp[i] = dp[i - 1] + len + 0.5,len = (len + 1) / 2;
            }
        }
        printf("%.4f
    ",dp[n]);
    }   
    int main() {
        solve();
      //  system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P6046:

    $我们考虑单独一个点的情况,首先,它要被杀掉那肯定是左边最近的和右边最近的位置来。$

    $其实就有一个比较自然的想法,E[x] = sum_{i = 1}^{n - 1}i * p[i],p[i] - 恰好活了i轮的概率$

    $但是这里恰好的概率很难算,所以就有一个新的期望计算式子E[i] = sum_{i = 1}^{n - 1}P[x >= i],P[i] - 存活轮数 >= i轮的概率$

    $然后我们来考虑存活概率>= i轮的概率,首先i位置和前面最近大于它的位置距离为pre,和后面最近大于它的位置为nxt:$

    $要杀了i,一种就是j轮里选完了pre,即C(n - 1 - pre,j - pre) / C(n - 1,j)  即n - 1 - pre个位置里选j - pre个$

    $然后右边选完了nxt同理,因为这两者都计算了选完了pre并且选完了nxt的情况,所以要容斥一下减去P(pre & nxt)$

    $所以P = 1 - P(pre) - P(nxt) + P(pre & nxt)$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int a[55],L[55],r[55];
    LL dp[55],C[55][55];
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = re * a % Mod;
            a = a * a % Mod;
            b >>= 1;
        }
        return re;
    }
    void solve() { 
        int n;scanf("%d",&n);
        for(int i = 1;i <= n;++i) scanf("%d",&a[i]),L[i] = r[i] = -1;
        for(int i = 1;i <= n;++i) {
            for(int j = i + 1;j <= n;++j) {
                if(a[j] > a[i]) {r[i] = j;break;}
            }
            for(int j = i - 1;j >= 1;--j) {
                if(a[j] > a[i]) {L[i] = j;break;}
            }
        }
        C[0][0] = 1;
        for(int i = 1;i <= 50;++i) {
            C[i - 1][0] = 1;
            for(int j = 1;j <= 50;++j) {
                C[i][j] = ADD(C[i - 1][j],C[i - 1][j - 1]);
            }
        }
        for(int i = 1;i <= n;++i) {
            int d1 = -1,d2 = -1;
            if(L[i] != -1) d1 = i - L[i];
            if(r[i] != -1) d2 = r[i] - i;
            if(a[i] == n) {dp[i] = n - 1;continue;}
            LL tmp = 0;
            for(int j = 1;j <= n - 1;++j) {
                LL p = 1;
                LL p1 = MUL(C[n - 1 - d1][j - d1],quick_mi(C[n - 1][j],Mod - 2));
                LL p2 = MUL(C[n - 1 - d2][j - d2],quick_mi(C[n - 1][j],Mod - 2));
                LL p3 = MUL(C[n - 1 - d1 - d2][j - d1 - d2],quick_mi(C[n - 1][j],Mod - 2));
                if(d1 != -1 && d2 != -1) p = 1 - p1 - p2 + p3;
                else if(d1 != -1) p = 1 - p1;
                else if(d2 != -1) p = 1 - p2;
                p %= Mod;
                p = (p + Mod) % Mod;
                tmp = ADD(tmp,p);
            }    
            dp[i] = tmp;
        }
        for(int i = 1;i <= n;++i) printf("%lld%c",dp[i],i == n ? '
    ' : ' ');
    
    }   
    int main() {
        solve();
       // system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/CF453A:

    $这题其实不难,主要瓶颈在于计算选了k轮最大值为i的概率$

    $这里就要用到容斥来算了,真的很妙$

    $投了n轮,全在1 ~ i - 1的概率 = (i - 1 / m) ^ n,投了n轮,全在1 ~ i的概率 = (i / m) ^ n,显然最大值为i的概率 = (i / m) ^ n  -  (i - 1 / m) ^ n$

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    LL quick_mi(LL a,LL b) {
        LL re = 1;
        while(b) {
            if(b & 1) re = re * a;
            a = a * a;
            b >>= 1;
        }
        return re;
    }
    void solve() { 
        int m,n;scanf("%d %d",&m,&n);
        double ans = 0;
        for(int i = 1;i <= m;++i) {
            double ma = 1.0 * i * (pow(1.0 * i / m,n) - pow(1.0 * (i - 1) / m,n));
            ans += ma;
        }
        printf("%.10f
    ",ans);
    }   
    int main() {
        solve();
      //  system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/P3802:

    这题有点玄妙了。我们可以求得前7个组成的概率a1 / n * a2 / (n - 1)  * a3 / (n - 2) * a4 / (n - 3) * a5 / (n - 4) * a6 / (n - 5) * a7 / (n - 6)

    然后因为期望具有线性可加性,E[8] = E[7] + E[1] = E[7],以此类推得出E[x > 7] = E[7],所以最后答案就是(n - 6) * E[7].

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    int a[10];
    void solve() { 
        int n = 0;
        for(int i = 1;i <= 7;++i) scanf("%d",&a[i]),n += a[i];
        if(n < 7) printf("0.000
    ");
        else {
            double ans = 1,f = 1,f2 = 1;
            for(int i = 1;i <= 7;++i) {
                double ma = a[i] * 1.0 / (n - i + 1);
                ans *= ma; 
            }
            LL ma = 1;
            for(int i = 1;i <= 7;++i) ma *= i;
            ans = ans * ma;
            ans *= (n - 6);
            printf("%.3f
    ",ans);
        }
    
    }   
    int main() {
        solve();
       // system("pause");
        return 0;
    }
    View Code

    https://www.luogu.com.cn/problem/CF16E:

    这里正着推的状压,不能找到问题。

    所以要倒着推,然后注意中间还要乘上存活集合为i里选中2条鱼的概率。

    // Author: levil
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    typedef long double ld;
    typedef pair<int,int> pii;
    const int N = 3e5 + 5;
    const int M = 1e6 + 5;
    const LL Mod = 998244353;
    #define INF 1e9
    #define dbg(ax) cout << "now this num is " << ax << endl;
    inline long long ADD(long long x,long long y) {
        if(x + y < 0) return ((x + y) % Mod + Mod) % Mod;
        return (x + y) % Mod;
    }
    inline long long MUL(long long x,long long y) {
        if(x * y < 0) return ((x * y) % Mod + Mod) % Mod;
        return x * y % Mod;
    }
    inline long long DEC(long long x,long long y) {
        if(x - y < 0) return (x - y + Mod) % Mod;
        return (x - y) % Mod;
    }
    
    double a[18][18],dp[1 << 18];//dp[i] - 集合i里的鱼都存活的概率
    int cnt[1 << 18];
    void solve() {
        int n;scanf("%d",&n);
        for(int i = 0;i < (1 << n);++i) {
            int k = 0;
            for(int j = 0;j < n;++j) {
                if(((i >> j) & 1) == 1) k++; 
            }
            cnt[i] = k;
        }
        for(int i = 0;i < n;++i) {
            for(int j = 0;j < n;++j) scanf("%lf",&a[i][j]);
        }
        memset(dp,0,sizeof(dp));
        dp[(1 << n) - 1] = 1;
        for(int i = (1 << n) - 2;i >= 0;--i) {
            for(int j = 0;j < n;++j) {
                if(((i >> j) & 1) == 0) continue;
                for(int k = 0;k < n;++k) {
                    if(((i >> k) & 1) == 0) {
                        dp[i] += dp[i | (1 << k)] * a[j][k] * 2.0 / (cnt[i] * (cnt[i] + 1));     
                    }
                }
            }
        }
        for(int i = 0;i < n;++i) printf("%.6f
    ",dp[1 << i]);
    
    }   
    int main() {
        solve();
        system("pause");
        return 0;
    }
    View Code
  • 相关阅读:
    PhoneGap 的文件 api
    81-POJ-Wall(计算几何)
    12-凸包模板-计算几何
    80-计算几何-奶牛
    79-多边形的面积-计算几何
    78-直线相交-计算几何
    11-欧拉函数详解
    76-Relatives-欧拉函数
    29-中国剩余定理CRT
    2018.3.12 Leecode习题 给定一个整数数列,找出其中和为特定值的那两个数。
  • 原文地址:https://www.cnblogs.com/zwjzwj/p/15505169.html
Copyright © 2011-2022 走看看