【题解】列队春游

思路分析

首先对于每一个 \(i\),可以处理不小于其的个数与小于其的个数(不包括自己),为了方便,分别表示成 \(big_i\)\(small_i\)

对于每一个小朋友,枚举其所在位置 \(j\),其站在这里的概率为 \(\dfrac{1}{n}\)

第三层循环枚举其视野,即 \(pre_i\),为了方便用 \(k\) 表示,当然 \(k\le j\) 那么我们需要:

  1. 其前 \(k-1\) 个人都比他矮。
  2. \(k\) 个人不低于他。

那么显然满足条件 \(1\) 的概率为 \(\dfrac{A_{small_i}^{k-1}}{A_{n-1}^{k-1}}\)

满足第 \(2\) 个条件的概率为 \(\dfrac{big_i}{n-k}\),即去了其自身和他前面 \(k-1\) 个人,剩下 \(n-k\) 个人中站在其前第 \(k\) 个人身高不小于他的概率。

那么综上所述对于一般情况下,对于第 \(i\) 个小朋友,他站在第 \(j\) 个位置,\(pre_i=k\) 时,其对于期望的贡献为:

\[\dfrac{1}{n}\times\dfrac{A_{small_i}^{k-1}}{A_{n-1}^{k-1}}\times\dfrac{big_i}{n-k}\times k \]

同时其还存在特殊情况,没有人能挡住他,即 \(j=k\) 时,要单独计算其贡献,此时贡献就是没有人能挡住他的概率 \(\times\) 其站在这个位置上的概率 \(\times\) 此时视野,和之前的区别就是没了其前第 \(k\) 个人不比他低的概率了,那么就是:

\[\dfrac{1}{n}\times\dfrac{A_{small_i}^{j-1}}{A_{n-1}^{j-1}}\times j \]

复杂度优化

此时的复杂度约为 \(O(n^4)\),虽然跑不满但是不允许,我们发现 \(\dfrac{A_{small_i}^{k-1}}{A_{n-1}^{k-1}}\) 在一次 \(i\) 的循环中除了 \(k\) 这个变量别的变量始终不变,故此可以递推,从而使复杂度降为 \(O(n^3)\)

递推式很简单,每次 \(k+1\) 时使其 \(\times\dfrac{small_i-k+1}{n-k}\) 即可。

注意\(\dfrac{A_{small_i}^{k-1}}{A_{n-1}^{k-1}}\) 不可能为负,所以为负时另其为 \(0\) 或直接结束本轮循环即可。

代码如下

#include<bits/stdc++.h>
// #define int long long 
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=310;
template<typename Tp> inline void read(Tp&x)
{
    x=0;register bool z=true;
    register char c=getchar();
    for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
    for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
    x=(z?x:~x+1);
}
void wt(int x){if(x>9)wt(x/10);putchar((x%10)+'0');}
void write(int x){if(x<0)putchar('-'),x=~x+1;wt(x);}
int n,h[N],d[N];
double ans;
double P(int d,int m,int n)
{
    int up=1,down=1;
    for(int i=d-m+1;i<=n-m;i++) up*=i;
    for(int i=d+1;i<=n;i++) down*=i;
    return (double)up/(double)down;
}
signed main()
{
    read(n);
    for(int i=1;i<=n;i++) read(h[i]);
    sort(h+1,h+1+n);
    for(int i=1;i<=n;i++)
    {
        int t=lower_bound(h+1,h+1+n,h[i])-h;
        d[i]=t-1;  
    }
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            double p=1; int v=d[i];
            for(int k=1;k<=j-1;k++)
                ans+=(double)k*p*(double)(n-d[i]-1)/(double)(n-k)/(double)(n),
                p*=(double)(v)/(double)(n-k),
                v-=(v>0);
            ans+=(double)(j)*(double)(p)/(double)(n);
        }
    printf("%.2lf",ans);
}
posted @ 2024-06-29 17:34  卡布叻_周深  阅读(15)  评论(0编辑  收藏  举报