HDU dice DP求期望+推公式

题意:
一个m边形的骰子,求连续投出n个相同的面,和m个两两不同的面的期望次数。
solution:
(f_i)表示已经连续投出i个相同的面,到连续投出n个还需要的期望次数.

(g_i)类似的表示第二种问题的期望次数。

对于(f_i) ,有两种情况:

① 投出了和前i个相同的面,转移到了(f_{i+1}) ,那么(f_i+=(f_{i+1}+1)*frac{1}{m})

② 投出了一个不同的面,转移到了(f_1),那么(f_i+=(f_1+1)*frac{m-1}{m})

综上,(f_i=(f_{i+1}+1)*frac{1}{m}+(f_1+1)*frac{m-1}{m}=f_{i+1}*frac{1}{m}+f_1*frac{m-1}{m}+1)

继续整理得到:(m*f_i=m+(m-1)*f_1+f_{i+1})

同理的话有:(m*f_{i+1}=m+(m-1)*f_1+f_{i+2})

两式相减得到:(m*(f_{i+1}-f_i)=f_{i+2}-f_{i+1})

可以发现,这成一个等比数列:

[f_0-f_1=1\ f_1-f_2=m\ …\ f_{n-1}-f_n=m^{n-1} ]

运用等比数列求和公式可得:(ans=frac{m*(1-m^{n-1})}{1-m}+1)

对于(g_i)

① 投出了和前i个都不同的面,转移到了(g_{i+1}) ,那么(g_i+=(g_{i+1}+1)*frac{m-i}{m})

② 投出了以前出现过的面,那么可能转移到了(g_1,g_2,…g_i),那么(g_i+=sum_{1≤j≤i}{(g_j+1)*frac{1}{m}})

综上,(g_i=(g_{i+1}+1)*frac{m-i}{m}+sum_{1≤j≤i}{(g_j+1)*frac{1}{m}}=g_{i+1}*frac{m-i}{m}+frac{1}{m}*sum_{1≤j≤i}{g_j}+1)

同上面(f_i)类似的处理之后,可以同样的得到(g_i-g_{i+1}=frac{m}{m-i}*(g_{i+1}-g_{i+2})),直接递推一下即可。

code:

#include<cmath>
#include<string>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define IL inline
#define LL long long
#define DB double
using namespace std;

const int N=1e6+1;

int n,m;
DB ans,s[N];

IL int qpow(int x,int p) {
	RG int ans=1;
	for(;p;p>>=1,x*=x)
		if(p&1) ans*=x;
	return ans;
}

int main()
{
   	RG int i,T,typ;
	while(scanf("%d",&T)!=EOF) {
		while(T--) {
			scanf("%d%d%d",&typ,&n,&m);
			if(typ==0) printf("%.9lf
",(DB)n*(1-qpow(n,m-1))/(1-n)+1);
			else {
				ans=0,s[0]=1;
				for(i=1;i<m;++i) s[i]=s[i-1]*n/(n-i);
				for(i=0;i<m;++i) ans+=s[i];
				printf("%.9lf
",ans);
			}
		}
	}
	return 0;
}


原文地址:https://www.cnblogs.com/Bhllx/p/10848859.html