数学期望整理

1.期望DP

洛谷P1365 WJMZBMR打osu! / Easy

题目入口

题解

f [ i ] f[i] f[i]表示到第i个字符的期望长度, g [ i ] g[i] g[i]表示以第i个字符为结尾的连续o串长度的期望,此时就有三种情况
s [ i ] = = o 时 , f [ i ] = f [ i − 1 ] + ( g [ i − 1 ] + 1 ) 2 − g [ i − 1 ] 2 = f [ i − 1 ] + 2 ∗ g [ i − 1 ] + 1 , g [ i ] = g [ i − 1 ] + 1 s[i] == o 时, f[i] = f[i - 1] + (g[i-1] + 1)^2 -g[i-1]^2 = f[i - 1] + 2 * g[i - 1] + 1,g[i] = g[i -1] + 1 s[i]==o,f[i]=f[i1]+(g[i1]+1)2g[i1]2=f[i1]+2g[i1]+1,g[i]=g[i1]+1
当 s [ i ] = = x 时 , g [ i ] = 0 , f [ i ] = f [ i − 1 ] 当s[i] == x时,g[i] = 0,f[i] = f[i - 1] s[i]==x,g[i]=0,f[i]=f[i1]
当 s [ i ] = = ? 时 , f [ i ] = f [ i ] + ( 2 ∗ g [ i − 1 ] + 1.0 ) ∗ p , g [ i ] = ( g [ i − 1 ] + 1 ) ∗ p ( p 为 ? 为 o 的 概 率 , 这 题 是 0.5 ) 当s[i] == ?时,f[i] = f[i] + (2 * g[i - 1] + 1.0) * p,g[i]=(g[i - 1] + 1)*p(p为?为o的概率,这题是0.5) s[i]==?,f[i]=f[i]+(2g[i1]+1.0)p,g[i]=(g[i1]+1)p(p?o0.5)

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 3e5 + 5;
double f[N], g[N];
char s[N];
int main() {
    int n;
    cin >> n >> s + 1;
    for(int i = 1; i <= n; i ++ ) {
        if(s[i] == 'o') {
            g[i] = g[i - 1] + 1.0;
            f[i] = f[i - 1] + 2.0 * g[i - 1] + 1.0;
        } else if(s[i] == 'x') {
            g[i] = 0;
            f[i] = f[i - 1];
        } else if(s[i] == '?') {
            g[i] = (g[i - 1] + 1.0) / 2.0;
            f[i] = f[i - 1] + (2.0 * g[i - 1] + 1.0) / 2.0;
        }
    }
    printf("%.4lf", f[n]);
    return 0;
}

洛谷P1654 OSU!

题目入口

题解

本题和上题差不多,不同的是本题需要维护长度 l e n len len l e n 2 len^2 len2的期望,注意不能只维护 l e n len len的期望,因为 E ( x 2 ) ≠ E ( x ) 2 E(x^2)\neq E(x)^2 E(x2)=E(x)2

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
double p;
double f[N]; // 到第i个的期望长度
double a[N], b[N]; // len的期望 和 len方的期望
double cal(double x) {
    return x * x * x;
}
int main() {
    cin.tie(0);
    cout.tie(0);
    ios::sync_with_stdio(0);
    int n;
    cin >> n;
    double res = 0;
    double len = 0;
    double p;
    for(int i = 1; i <= n; i ++ ) {
        cin >> p;
        a[i] = (a[i - 1] + 1) * p;
        b[i] = (b[i - 1] + (2.0 * a[i - 1] + 1.0)) * p;
        f[i] = f[i - 1] + ((3.0 * b[i - 1] + 3.0 * a[i - 1] + 1.0)) * p;
    }
    printf("%.1lf", f[n]);
    return 0;
}

2.推公式

P4562 [JXOI2018]游戏

题目入口

题解

我们发现,对于一系列具有倍数关系数字2,4,6,8,检查时间其实是由他们种最小的数所决定的,以样例为例,将2,4分为一类,3分为一类,最后的检查时间是由2和3的位置所决定,所以可以枚举所有可能的时间,排列组合一下即可

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod = 1e9 + 7;
const int N = 1e7 + 5;
int fac[N], infac[N];
int pre[N];
bool vis[N];
int sz[N];

int qpow(int a, int n, int mod) {
    int res = 1;
    while(n) {
        if(n & 1) res = res * a % mod;
        a = a * a % mod;
        n >>= 1;
    }
    return res;
}
void init(int n) { //预处理阶乘和逆元
    fac[0] = 1;
    infac[0] = 1;
    for(int i = 1; i <= n; i ++ ) fac[i] = fac[i - 1] * i % mod;
    infac[n] = qpow(fac[n], mod - 2, mod);
    for(int i = n - 1; i >= 1; i -- ) {
        infac[i] = infac[i + 1] * (i + 1) % mod;
    }

    //for(int i = 1; i <= 10; i ++ ) cout << fac[i] << " ";
    //cout << endl;
    //for(int j = 1; j <= 10; j ++ ) cout << infac[j] << " ";
    //cout << endl;
}

inline int find(int x) {
    return x == pre[x] ? x : pre[x] = find(pre[x]);
}

int C(int a, int b) {
    return fac[a] % mod * infac[a - b] % mod * infac[b] % mod;
}

signed main() {
    int l, r;
    cin >> l >> r;
    init(r + 1);
    int n = r - l + 1;
    int x = 0; // x为最小的数的个数
    for(int i = l; i <= r; i ++ ) {
        if(vis[i]) continue;
        x ++ ;
        for(int j = 2; j * i <= r; j ++ ) {
            if(vis[i * j]) continue;
            vis[i * j] = true;
            //cout << i << " " << j << endl;
        }
    }

    //for(int i = l; i <= r; i ++ ) cout << pre[i] << " ";
    int res = 0;

    //cout << C(5, 3) << endl;
    //cout << x << endl;
    for(int i = x; i <= n; i ++ ) { // 枚举可能的时间
        res += x * C(n - x, i - x) % mod * fac[i - 1] % mod * fac[n - i] % mod * i % mod;
        res %= mod;
    }

// 对于时间是i的情况,说明x个数必须在前i个位置且有一个处于第i个位置,于是固定第i个位置,前面和后面全排列即可
    cout << res << endl;
    return 0;
}

P3802 小魔女帕琪

题目入口

题解

如果我们能知道每七个连续的晶体释放魔法的概率,将所有的可能性加起来便是结果,令 a 1 , a 2 . . . a 7 为 每 种 属 性 的 晶 体 数 量 , a_1,a_2...a_7为每种属性的晶体数量, a1,a2...a7以前七个为例,如果能施放魔法,概率必为 7 ! × C n a 1 × C n − 1 a 2 . . . × C n − 6 a 7 7!\times C_n^{a1}\times C_{n-1}^{a2}...\times C_{n - 6}^{a7} 7!×Cna1×Cn1a2...×Cn6a7,7!是因为释放一次魔法时每种属性的晶体位置不确定,接下来我们可以感性的理解一下,对于抽签,在每次不知道前者结果时概率时一样的,本题也可以这么理解,之后每七个能释放魔法的概率均相同,由于长度为7的串一共有 n − 6 n-6 n6个,最后答案乘上即可

代码

#include<bits/stdc++.h>
using namespace std;
const int N = 10;
double f[N], g[N];
int a[N];
double res = 1;
int main() {
    int n = 0;
    for(int i = 1; i <= 7; i ++ ) {
        cin >> a[i];
        n += a[i];
    }

    int fac7 = 1 * 2 * 3 * 4 * 5 * 6 * 7;
    bool flag = true;
    for(int i = 1; i <= 7; i ++ ) {
        if(n - i + 1 == 0) {
            flag = false;
            break;
        }
        res *= a[i] * 1.0 / (n - i + 1);
    }
    if(!flag) cout << "0.000" << endl;
    else {
        res = res * fac7 * (n - 6);
        printf("%.3lf", res);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值