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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值