Codeforces626 D. Jerry‘s Protest(概率)
Posted live4m
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces626 D. Jerry‘s Protest(概率)相关的知识,希望对你有一定的参考价值。
题意:
解法:
枚举点对(i,j),其中a[i]<a[j],表示第三次的结果,那么差值dif=a[j]-a[i],
对于这个点对,前两次需要满足差值和<=dif-1,
我们只需要想办法预处理出前两次差值和<=dif-1的概率即可.
点对总数量为n*(n-1)/2,
设cnt[i]为前两次的每一次操作中,差值i出现的次数,
第三次是a[i]<a[j],因此前两次一定是a[i]>a[j]的.
那么每次差值i出现的概率=cnt[i]/tot.
令d[i]为前两次差值和为i的概率,
d[i+j]=(cnt[i]/tot)*(cnt[j]/tot),
这个可以O(n^2)预处理.
然后对d[]计算前缀和,那么d[i]就是差值和<=i的概率了.
最后像开始说的那样,枚举点对计算dif,累加d[dif-1]就是答案.
code:
#include<bits/stdc++.h>
#define int long long
using namespace std;
double d[5555];//d[i]表示前两次差值和为i的概率
int cnt[5555];//cnt[i]表示一次操作差值i的出现次数
int a[2222];
int n;
void solve(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
sort(a+1,a+1+n);
int tot=n*(n-1)/2;
for(int i=1;i<=n;i++){
for(int j=1;j<i;j++){
cnt[a[i]-a[j]]++;
}
}
for(int i=1;i<=5000;i++){
for(int j=1;j<=5000;j++){
if(i+j<=5000){
d[i+j]+=(1.0*cnt[i]/tot)*(1.0*cnt[j]/tot);
}else break;
}
}
double ans=0;
for(int i=1;i<=5000;i++)d[i]+=d[i-1];
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
int dif=a[j]-a[i];
ans+=d[dif-1]/tot;
}
}
printf("%.10f\\n",ans);
}
signed main(){
solve();
return 0;
}
以上是关于Codeforces626 D. Jerry‘s Protest(概率)的主要内容,如果未能解决你的问题,请参考以下文章
Codeforces Round #626 Div2 D. Present(位掩码,二分)
排序规律Codeforces Round #254 (Div. 2) - D. Rooter's Song
codeforces1364 D. Ehab's Last Corollary(最小环)