CF846F - Random Query

题意:对于一个序列,每次随机选择两个数 \(l,r\),如果 \(l\gt r\) 就交换,求 \(l,r\) 中本质不同的数个数的期望。

我们发现,在所有的 \(n^2\) 个选择方案中,其实就是 \(l<r\) 的区间,会被选择 \(2\) 次,\(l=r\) 的区间会被选择 \(1\) 次。

如何计算呢?在同一个区间中,我们只计算最左边的一个数所造成的贡献。那么就很显而易见,假如当前点是 \(i\),上一个和它相同的位置是 \(lst_i\),那么它会在左端点在 \((lst_i,i]\),右端点在 \([i,n]\) 的所有区间中作出一次贡献。但是我们只需要 \(l<r\) 的区间,那么就要去掉 \([i,i]\) 的贡献,或者把左端点在 \(i\) 的情况分开计算。这样得到所有区间贡献的总和 \(res\)

所有 \(l=r\) 的区间贡献总和是 \(n\)。答案就是 \(\dfrac{res+n}{n^2}\)

#include<bits/stdc++.h>
using namespace std;
#define rd(i,n) for(int i=0;i<n;i++)
#define rp(i,n) for(int i=1;i<=n;i++)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=b;i>=a;i--)
#define st string
#define vt vector
#define pb push_back
//#define int long long
typedef long long ll;
typedef long double ld;
typedef pair<int,int> pii;
typedef pair<ll,ll> pll;
ll n,a[1000005];
int lst[1000005];
signed main(){
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	cin>>n;
	rp(i,n)cin>>a[i];
	ll sum=n*n;
	ll ans=0;
	rp(i,n){
		ans+=2*(i-1-lst[a[i]])*(n-i+1);
		ans+=2*(1)*(n-i);
		lst[a[i]]=i;
	}
	cout<<fixed<<setprecision(6)<<(ld)(ans+n)/sum<<endl;
	return 0;
}
//Crayan_r

posted @ 2023-02-23 17:49  jucason_xu  阅读(14)  评论(0编辑  收藏  举报