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\) ,则
故而 \(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)\) ,易知
当 \(|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} = 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\) ,即
所以可以在求 \(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;
}