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

Codeforces 626C. Block Towers

codeforces1364 D. Ehab's Last Corollary(最小环)

Codeforces Round #651 (Div. 2) D. Odd-Even Subsequence(二分)

CodeForces - 626D