题目链接
题目讲解先看另一位博主的讲解吧,我是看的他的博客比这写出来的这道题:
博客链接
求第一个位置时,选中有1的方案及相应的概率:
1-36% 2-25% 3-39%
1-24% 2-25% 4-51%
1-1% 2-25% 5-74%
1-24% 3-64% 4-12%
1-1% 3-64% 5-35%
1-1% 4-76% 5-23%
1号位置的概率期望为(36+24+1+24+1+1)/C(5,3) = 8.7
对于每一个位置i,f[i][j]表示第i个位置被选中,且其上面恰好有j个相邻的位置没有被选中时,i在k个位置中被选中的概率。f[i][j] = f[i-1][j-1]+a[i]。
当i上有j个位置未被选中时,第i、i-j-1位置已被固定,所以这样的情况一共有C(n-j-2,k-2)种。
对于每个i枚举每个j,答案累加C(n-j-2,k-2)f[i][j]/C(n,k)。
k=1时要特殊处理。每个位置答案均为1/n。
这道题目后来看完之后一点一点搞懂啦
先是我们需要一个500500的c几几的答案图,这个直接调用就非常方便
可以看出啦这就是一个杨辉三角,也就是符合我们想要的c几几的答案矩阵表。
然后另一个是f矩阵:这个矩阵也是对应存储第i个被选中,而且刚好上面有j个空间的概率需要降下来加在一起的整个概率和。
这个也要看一下图才能真正知道却是这样存却是对啦。
然后这个题目就是代码编辑:::当i上有j个位置未被选中时,第i、i-j-1位置已被固定,所以这样的情况一共有C(n-j-2,k-2)种。
对于每个i枚举每个j,答案累加C(n-j-2,k-2)*f[i][j]/C(n,k)。
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <math.h>
#include <string>
#include <vector>
#include <map>
using namespace std;
#define esp 1e-5
const int N=520;
#define rep(i,start,endd) for(i=start;i<=endd;i++)
int n,k;
double a[N],c[N][N],f[N][N];//用来存储c几几得到的数字大小;
//f数组用来存储概率
void init(){
c[0][0]=1.0;
for(int i=1;i<505;i++){
c[i][0]=c[i][i]=1.0;// 这个俩地方是每一行的开头和结尾,都不是下面那个式子求出来的。
//这个c数组求完是个杨辉三角。所以这样求。。。。嗯~~~;
for(int j=1;j<=i-1;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
//刚刚求的是c几几的网格表
for(int i=1;i<=n;i++){//这个边界n-1和n都行
f[1][i]=f[1][i-1]+a[n-i+1];
}
for(int i=2;i<=n;i++){//注意边界!
for(int j=1;j<=n;j++)//注意边界这个j的边界也是一样n和n-1都行
f[i][j]=f[i-1][j-1]+a[i];
}
//这里就是求的是概率表格(在i被选中之后,上面有着连续的j的没有被选的概率之和。)
}
int main()
{
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
f[i][0]=a[i];
}
if(k==1){//选谁都能连起来。所以是一百;;;
for(int i=1;i<=n;i++){
if(i!=1)printf(" ");
printf("%.10f",100.0/(1.0*n));
}
puts("");
return 0;//别忘啦加我就是这里没错啦好几遍。
}
init();
for(int i=1;i<=n;i++){
double ans=0.0;
for(int p=0;p<=n-k;p++)//只能有n-k个空格来用做j
{
ans+=c[n-p-2][k-2]*f[i][p];
}
if(i!=1)printf(" ");
printf("%.10f",ans/c[n][k]);
}
puts("");
return 0;
}