NOI模拟(3.6)Assignment

Description

随机生成一个长度为m且每个元素都为1~n之间的整数的单调不下降序列 ~ (即序列的 (i>1)都不小于 ),(随机生成指每一种可能的序列都等概率被生成)。请问这个序列的众数出现次数期望是多少,有多组数据。
 

Input

第一行一个整数T,为数据组数
接下来T行,每行两个被空格隔开的正整数m,n为序列长度和元素的值的上界。

Output

一共T行,每一行一个实数,为每组数据的答案
如果你的答案与标准答案的误差不超过1e-5,则视为正确
 

Sample Input

4
1 5
3 3
2 9
9 6

Sample Output

1.0000000000
2.2000000000
1.2000000000
4.3146853147
 

Data Constraint

对于10%的数据:n,m<=5,T=1
对于另外20%的数据:m<=15,T<=5
对于另外20%的数据:n,m<=50, T<=5
对于100%的数据:1<=m<=250,1<=n<=1e9,T<=15
 

Hint

对于3 3这一组数据,有以下情况(x为众数出现的次数)
1 1 1 (x = 3) 
1 1 2 (x = 2) 
1 1 3 (x = 2) 
1 2 2 (x = 2) 
1 2 3 (x = 1) 
1 3 3 (x = 2) 
2 2 2 (x = 3) 
2 2 3 (x = 2) 
2 3 3 (x = 2) 
3 3 3 (x = 3) 
所以期望是1/10+2*6/10+3*3/10=22/10

Solution

看看应该是一道dp

可以有这样一个思路

令f(i,j)为构造出的序列长度为i,当前填入序列第j种数,为了限制众数的出现次数,要去除所有众数出现次数大于限定的情况

因此,f(k,i,j)=f(k,i-1,j-1)+f(k,i-1,j)-f(k,i-k-1,j-1),其中k代表限定众数出现次数为k

最后乘上一个组合数就是答案了

#include <stdio.h>
#include <string.h>

template<class T> inline void read(T &x)
	{
	int c=getchar();
	for(x=0;c<48||c>57;c=getchar());
	for(;c>47&&c<58;c=getchar())x=(x<<1)+(x<<3)+c-48;
	}

int T,m,n;
long double C[255],f[255][255][255],g[255],ans;

int main()
	{
	freopen("assignment.in","r",stdin);
	freopen("assignment.out","w",stdout);
	for(int k=1;k<=250;k++)
		{
		f[k][0][0]=1;
		for(int i=1;i<=250;i++)
			for(int j=1;j<=i;j++)
				{
				f[k][i][j]=f[k][i-1][j-1]+f[k][i-1][j];
				if(i-k-1>=0)f[k][i][j]-=f[k][i-k-1][j-1];
				}
		}
	for(read(T);T;T--)
		{
		read(m),read(n);
		C[0]=1;
		for(int i=1;i<=m;i++)
			C[i]=C[i-1]*(n-i+1)/i;
		for(int k=1;k<=m;k++)
			{
			g[k]=0;
			for(int j=1;j<=m;j++)
				g[k]+=f[k][m][j]*C[j];
			}
		ans=0;
		for(int k=1;k<=m;k++)
			ans+=k*(g[k]-g[k-1])/g[m];
		printf("%.6f\n",(double)ans);
		}
	fclose(stdin);
	fclose(stdout);
	return 0;
	}

  

posted @ 2017-03-08 17:30  keshuqi  阅读(471)  评论(0编辑  收藏  举报