【Codeforces1187F】Expected Square Beauty

题目链接:

【Codeforces1187F】Expected Square Beauty

题目描述:

有一个长度为 $ n $ 的数列,第 $ i $ 个数的取值范围为 $ [l_i, r_i] $ ,定义一个数列的价值为这个数列极长连续相同段的个数,求一个数列价值的平方期望,对 $ 10^9 + 7 $ 取模 。
$ n \leq 200000 $ 。

做法:

定义 $ F(x) $ 为数列的价值, $ I_i(x) $ 为数列中第 $ i $ 项与第 $ i - 1 $ 项是否不同 $ (I_i(x) = [x_i \neq x_{i - 1}]) $ ,则有 $ F(x) = \sum_{i = 1}^{n} I_i(x) $ 。
\[ E(B(x)^2) = E(\sum_{i = 1}^{n}I_i(x)\sum_{j = 1}^{n}I_j(x))\\ = E(\sum_{i = 1}^{n}\sum_{j = 1}^{n}I_i(x)I_j(x))\\ = \sum_{i = 1}^{n}\sum_{j = 1}^{n}E(I_i(x)I_j(x)) \]
考虑计算 $ E(I_i(x)I_j(x)) $ ,分三种情况考虑。
当 $ i = j $ 时, $ E(I_i(x)I_j(x)) = E(I_i(x)) $ 。
当 $ | i - j | > 1 $ 时, $ I_i(x), I_j(x) $ 互不影响, $ E(I_i(x)I_j(x)) = E(I_i(x))E(I_j(x)) $ 。
当 $ | i - j | = 1 $ 时,仅考虑 $ j = i + 1 $ 的贡献( $ i = j + 1 $ 同理)。$ E(I_i(x) I_j(x)) = P(x_{i - 1} \neq x_{i} \land x_{i} \neq x_{i + 1}) $ 。考虑容斥, $ E(I_i(x) I_j(x)) = 1 - p_{i} - p_{i + 1} + P(x_{i - 1} = x_{i} \land x_{i} = x_{i + 1}) $ ,就可以计算了。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const int N = 200010;
int n, l[N], r[N], inv[N], ans;
int e[N], pre[N], suf[N];

inline int add(const int &x, const int &y) {
    return x + y < mod ? x + y : x + y - mod;
}
inline int sub(const int &x, const int &y) {
    return x - y < 0 ? x - y + mod : x - y;
}
inline int mul(const int &x, const int &y) { return (int)((ll)x * y % mod); }
int ksm(int x, int y = mod - 2) {
    int ss = 1; for(; y; y >>= 1, x = mul(x, x)) if(y & 1) ss = mul(ss, x);
    return ss;
}
int calc(int x, int y, int z) {
    if(!x) return 0;
    int w = min(min(r[y], r[x]), r[z]) - max(max(l[y], l[x]), l[z]) + 1;
    if(w < 0) w = 0;
    int val = mul(mul(inv[x], inv[y]), inv[z]); return mul(w, val);
}
int main() {
    scanf("%d", &n);
    for(int i = 1; i <= n; i++) scanf("%d", &l[i]);
    for(int i = 1; i <= n; i++) scanf("%d", &r[i]);
    e[1] = 1, inv[1] = ksm(r[1] - l[1] + 1);
    for(int i = 2; i <= n; i++) {
        inv[i] = ksm(r[i] - l[i] + 1);
        e[i] = min(r[i], r[i - 1]) - max(l[i], l[i - 1]) + 1;
        if(e[i] < 0) e[i] = 0;
        e[i] = mul(e[i], mul(inv[i - 1], inv[i])), e[i] = sub(1, e[i]);
    }
    for(int i = 1; i <= n; i++) pre[i] = add(pre[i - 1], e[i]);
    for(int i = n; i >= 1; i--) suf[i] = add(suf[i + 1], e[i]);
    for(int i = 1; i <= n; i++) {
        if(i < n) ans = add(ans, mul(e[i], suf[i + 2]));
        if(i > 1) ans = add(ans, mul(e[i], pre[i - 2]));
    }
    for(int i = 1; i <= n; i++) ans = add(ans, e[i]);
    for(int i = 1; i < n; i++) {
        int sum = sub(1, add(sub(1, e[i + 1]), sub(1, e[i])));
        sum = add(sum, calc(i - 1, i, i + 1));
        ans = add(ans, add(sum, sum));
    }
    printf("%d\n", ans);
    return 0;
}

转载于:https://www.cnblogs.com/daniel14311531/p/11133122.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值