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;
}
posted @ 2026-01-28 19:30  Lappybreeze  阅读(17)  评论(0)    收藏  举报