CF846F 期望
XCPC的第一道期望题(并非)
原题地址
题目大意:
从1~n中选中两个数作为l,r,求选中区间内数的种类的期望。\((1\leq n\leq 1e6)\)
首先我们在高中时期就接触了这点:期望的和等于和的期望。
\(E(\sum X) = \sum E(X)\)
我们直接考虑暴力求对应区间类别数的情况,一共\(C_n^2 * 2\)种(因为l > r和相同位置的rl对调并不算同种)
所以只能从数组值来下手了。
这里的学习点在于,当我们标记对应前一次出现当前值x的时候我们枚举的区间不存在与x相同的情况。
也就是说,对于当前的下标index,可以作出贡献的区间是\((index - pre[a[i]])\)
作为我们的区间左端点L的范围,然后R从L自己右边的\((n - index + 1)\)任意选一个点就可以了,即使有和当前相同的点贡献也属于当前作出的。
这里(r,l)对调也算情况所以要\(\times 2\)
然后减去(l = r)重复计入的情况。
然后除我们可能存在的\(C_n^2 * 2(区间) + n(单点) = n^2\)种情况即可获得对应的期望。
最后,计算的时候不要忘了给所有涉及int的贡献数开ll否则会\(WA\;7\)
#include <bits/stdc++.h>
#include <iomanip>
#include <vector>
#define fi first
#define se second
#define pii pair<int, int>
using namespace std;
using ll = long long;
using LD = long double;
#define int long long
int T;
const ll inf = 3e18;
int n;
void solve() {
cin >> n;
vector<ll> a(n + 1), pre(1e6 + 7, 0);
for (int i = 1; i <= n; ++i) {
cin >> a[i];
}
ll ans = 0;
for (int i = 1; i <= n; ++i) {
ans += (i - pre[a[i]]) * (n - i + 1) * 2;
pre[a[i]] = i;
}
ans -= n;
cout << fixed << setprecision(6) << (LD)ans / (LD)(n * n) << '\n';
}
signed main() {
cin.tie(nullptr)->sync_with_stdio(0);
T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

浙公网安备 33010602011771号