题目
随机判分
G市进行了一场歌唱比赛,一般来说,选手唱完,评委打分,去掉最高,去掉最低,剩下的取平均分,就是选手的最终得分。
然而今天所有n个评委脑子都出了问题。他们只会从一个既定的分数集合中等概率地选一个没被前面的评委打过的分进行打分。
给定n和这个分数集合,求一个选手的得分的期望值。
输入格式
第一行是两个数字n和m,表示评委数量和分数集合的大小
第二行是m个数字表示分数集合里的每个分数ai,保证ai两两不同。
输出格式
输出共1行,选手的期望得分,保留5位小数。
输入样例
3 4
1 2 3 4
输出样例
2.50000
样例解释
评委打分4种可能:
[1,2,3]选手得分为2
[1,2,4]选手得分为2
[1,3,4]选手得分为3
[2,3,4]选手得分为3
数据范围
前20%的数据,n<=10
所有数据,3<=n<=m<=7000, ai<=10000
心路历程:
因为太久不打代码,看到题目就想到全排列。。光荣的忽略了数据范围。。结果只有二十分。。
没错就是前两个点
自闭(谁能想到它是道数论呢)(好的我知道只有我想不到)
思路:
通过分析(m个中选n个的方案数)及数列中每个数在方案数中出现的次数计算权重,每个数*权重/方案数/m-2即为答案
分析:
(我是真的不会打数学公式,画图见)
这时问题就转化成了怎样计算一般公式
这里可以自己把i=1,i=2,i=3……代入寻找规律(大佬也可以直接从i和i-1之间寻找一般规律)
然后就能找到递推式啦(愉快)
推的过程要自己想啊!(答案放在代码后面)
现在,已经推出了除了常数前一部分的规律,那后一部分应该怎么求呢?
代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <algorithm> using namespace std; int n,k,i,j; int a[7777]; double f[7777]; int c_nk,c_n1; int main() { freopen("random.in","r",stdin); freopen("random.out","w",stdout); scanf("%d%d",&k,&n); for (i=1;i<=n;i++) scanf("%d",a+i); sort(a+1,a+1+n); f[n]=1.0; c_nk=n-k; c_n1=n-1; for (i=n;i>=k;i--) { f[i-1]=f[i]*c_nk/c_n1; c_nk--; c_n1--; } for (i=1,j=n;i<=j;i++,j--) { f[i]=f[i]+f[j]; f[j]=f[i]; } double sum=0; for (i=1;i<=n;i++) sum=sum-f[i]*a[i]; for (i=1;i<=n;i++) sum=sum+a[i]; sum/=1.0*(k-2)*n/k; printf("%.5lf ",sum+1e-8); return 0; }
(这里直接引用老师的标程)
下面是上文思考的答案
就这样啦!
放个烟花吗?(嘻)