运动会(第一次接触概率DP的我黯然神伤)

运动会

题目描述:有n个项目,m个人,lzj每个项目的排名分别是a[1]…a[i],假设其他m-1 个人在每个子项目的比赛中获得各名次的概率相同,求他自己最后排名的期望值
样例
input
4 10
2
1
2
1
output
1.0000000000000

好难啊,好难难难难啊!!!!!!
看过题目基本就放弃了,因为对于概率和数学期望真的是两眼一抹黑,啥都不会,然后直接跳过没想到……今天的第一题看错题目了爆零了,第三题不知道哪里出问题了,今天就就就就爆零了!!!
贼难过。

———————————————废话分割线—————————————
题解:
1.直接暴力,20分,暴力求gcd,和gcd的区间
2。我的错误解法:误认为a[i]和a[j]的最大公因数即是a[i]到a[j]所有相邻的数的最小的最大公因数,贼**的做法,但是如果打法正确估计20~40之间
3.神奇概率DP
f[i][j]表示前i个项目,共获得j分数的期望人数,期望人数(可能获得名次的概率*人数),譬如说该人第五名,那么其余m-1个人都有可能排在前面四名,
dp[i][j]=∑ dp[i-1][j-k]/(m-1)
k=max(j-m,0),k!=a[i]

因为上一次比赛的分数在(j-m~j-1)之间的分数都可以得到一定的名次而得到这次的j分,所以都要叠加过来,再除以这次得到相应分数的几率(m-1)

所以每次都要遍历一遍dp,然而我们可以看到,他们是同样的除以一个(m-1),所以我们可以提取公因式,然后用前缀和来简化遍历的过程

(……)到这里,这道题我想了一天还是有些不懂,今天晚上回去我会研习一下数学期望及概率等东西,emmm这个东西其实还是理解就不难,就难在不能理解(皮一下)。

#include <bits/stdc++.h>
#define maxn 105
#define maxm 1005

using namespace std;

int n,m,q,l,r,a[maxn];
double ans,f[2][maxn*maxm],s[2][maxn*maxm];

int main()
{   
        //freopen("meeting.in","r",stdin);
        //freopen("meeting.out","w",stdout);
        scanf("%d%d",&n,&m);
        if (m==1) 
            {
                printf("1.00000000000000000\n");
                return 0;   
            }  
        for (int i=1;i<=n;i++)
            scanf("%d",&a[i]);
        f[0][0]=m-1;//f[i][j]表示前i项比赛得分为j的期望分数 
        s[0][0]=0;// 
        for (int i=1;i<=n*m+1;i++)  
            s[0][i]=m-1;  
        for (int i=1;i<=n;i++)
            {
                for (int j=0;j<=n*m;j++)
                    f[i%2][j]=s[i%2][j]=0;
                for (int j=1;j<=n*m;j++)
                    {
                        l=max(0,j-m);
                        r=j;
                        f[i%2][j]=(s[(i-1)%2][r]-s[(i-1)%2][l])/(m-1);
                        if (j-a[i]>=0)
                            f[i%2][j]-=f[(i-1)%2][j-a[i]]/(m-1);
                        s[i%2][j+1]=s[i%2][j]+f[i%2][j];
                    }
            }
        for(int i=1; i<=2; i++)
          {
            for (int j=1; j<=n*m; j++)
              cout<<s[i][j]<<' ';
             cout<<endl;
        }
        for (int i=1;i<=n;i++)
            q+=a[i];
        printf("%.16lf\n",s[n%2][q]+1);
        return 0;
}

!!!!!!!!!!!!!!!!!!!!我懂了!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!我想了一个下午只是在于我没有正确理解的方程的意思,在第三遍观看了rym大佬的题解之后终于领悟了!!!!!!!!本身我们要dp的这个方程,是用来求得分小于他的得分的期望,而不是他本身得到这个排名的概率!!!!!!!!!!!!!!!!!!!!!!!!!!!

因为是得分小于他的得分的期望,所以可以用他当前能得到的分数每次去除以可能比他排名低的人数,就是m-1!!!再用滚动数组来去,具体我明天再!!

猜你喜欢

转载自blog.csdn.net/beautiful_cxw/article/details/81104441