CF1187F Expected Square Beauty

原题传送门

简单题意


给定一个长度为 \(n\) 的数列 \(\{x_i\}\) ,定义 \(B(x)\) 为将 \(x\) 划分为所有元素都相等的子段的最小子段数。
对于任意 \(1 \leq i \leq n\) ,有 \(x_i\)\([l_i, r_i]\) 区间上等概率的任何一个数,给定 \(\{l_i\}, \{r_i\}\) 两个数组,求\(E((B(x))^2)\) 的值。

分析


题目中要求的是元素相等的子段数,即求出任意の相邻两个数不同的概率,再对其求和即可求出 \(B(x)\) 的期望值 \(E(B(x))\)

设相邻两数 \((x_{i - 1} , x_i)\) 不同的概率为 \(f_i = E([x_{i - 1} \neq x_i])\) ,两个数均会等概率的选取其区间中的所有数, 为了方便可以先计算两个数相同的概率 \(p\) ,则

\[f_i = 1 - p = 1 - \dfrac{max\{0, min\{r_{i - 1}, r_i\}, max\{l_{i -1}, l_i\}\}}{(r_{i - 1} - l_{i - 1} + 1)(r_i - l_i + 1)} \]

故而 \(E(B(x)) = E(\sum_{i = 1}^n [x_{i - 1} \neq x_i]) = \sum_{i = 1}^n f_i\) ,但是有一点值得注意 \(x_1\) 比较特殊 它前面并没有数,这时,我们可以在前面加一个 \(x_0\) ,其区间设为 \([0, 0]\) 。显而易见 \(f_1 = 1\)(划掉

因为题面要求是求出对 \(10^9 + 7\) 取模后的结果,我们可以预先对所有的区间长度 \(len_i = r_i - l_i + 1\)\(\mod (10^9 + 7)\) 下的逆元。

下面讨论 \(E((B(x))^2)\) ,易知

\[\begin{aligned} & E((B(x))^2) \\ & = E(B(x)B(x)) \\ & = E(\sum_{i = 1}^n [x_{i - 1} \neq x_i] \sum_{j = 1}^n [x_{j - 1} \neq x_j]) \\ \end{aligned} \]

\(|i - j| > 1\) 时,可以发现两者不存在相互依赖的关系,即有 \(E((B(x))^2) = f_if_j\)

\(i = j\) 时,\(E((B(x))^2) = f_i\)

\(|i - j| = 1\) 时,令 \(j = i + 1\)\(E((B(x))^2) = E([x_{i - 1} \neq x_i \wedge x_i \neq x_{i + 1}])\) ,可以通过容斥原理来计算

\[E([x_{i - 1} \neq x_i \wedge x_i \neq x_{i + 1}]) = 1 - E([x_{i - 1} = x_i]) - E([x_i = x_{i + 1}]) + E([x_{i - 1} = x_i = x_{i + 1}]) \]

其中 \(E([x_{i - 1} = x_i]) = 1 - f_i\)\(E([x_i = x_{i + 1}]) = 1 - f_{i + 1}\)\(E([x_{i - 1} = x_i = x_{i + 1}]) = \dfrac{max\{0, min\{r_{i - 1}, r_i, r_{i + 1}\}, max\{l_{i - 1}, l_i\, l_{i + 1}\}\}}{(r_{i - 1} - l_{i - 1} + 1)(r_i - l_i + 1)(r_{i + 1} - l_{i + 1} + 1)}\)

对于后两种情况,显然可以 \(\mathcal{O}(N)\) 处理。考虑到对称性,第一种情况可以先处理 \(i < j\) 的情况,然后对答案乘以 \(2\) ,即

\[ans = 2 \sum_{j = 3}^n \sum_{i = 1}^{j - 2} f_i f_j = 2 \sum_{j = 3}^n f_j \sum_{i = 1}^{j - 2} f_i \]

所以可以在求 \(f_i\) 的同时,求出上述式子,只需同时维护 \(f_i\)\(1\)\(i - 2\) 的前缀和即可,此外只要记录一下当前最后的前缀和就行,无须另外开一个数组记录前缀和。


Code

#include <bits/stdc++.h>

#define ll long long
#define rep(i, a, b) for (int i = a; i <= b; i++)

using namespace std;

const int N = 2e5 + 10;
const ll mod = 1e9 + 7;

ll n, l[N], r[N], len[N], inv[N], f[N];
ll sum, ans;

ll qpow(ll a, ll b)
{
    ll res = 1ll;
    while (b)
    {
        if (b & 1) res = res * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return res;
}

int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    cin >> n;
    rep (i, 1, n) cin >> l[i];
    rep (i, 1, n) cin >> r[i];
	
    inv[0] = 1;
    rep (i, 1, n)
    {
		//预处理每个数所在区间的长度及其逆元
        len[i] = r[i] - l[i] + 1;
        inv[i] = qpow(len[i], mod - 2);
		//求出 |i - j| >= 1 时的答案
        f[i] =(1 - 1ll * max(0ll, min(r[i], r[i - 1]) - max(l[i], l[i - 1]) + 1) * inv[i] % mod * inv[i - 1] % mod + mod) % mod;
        if (i > 2) sum = (sum + f[i - 2]) % mod;
        ans = ((ans + f[i]) % mod + sum * f[i] * 2ll % mod) % mod; 
    }
	//求出 |i - j| < 1 时的答案
    rep (i, 1, n - 1)
    {
        ll x, y;
        x = (1ll * (1 - (1 - f[i]) - (1 - f[i + 1])) % mod + mod) % mod;
        y = 1ll * max(0ll, min({r[i - 1], r[i], r[i + 1]}) - max({l[i - 1], l[i], l[i + 1]}) + 1) * inv[i - 1] % mod * inv[i] % mod * inv[i + 1] % mod;
        ans = (ans + 2ll * (x + y) % mod) % mod;
    }
    cout << ans << "\n";
    return 0;
}
posted @ 2022-01-05 20:59  circletime  阅读(91)  评论(0)    收藏  举报