期望的逆推 及 HDU 4652 Dice

Problem

HDU

Solution

鉴于Rayment的期望dp实在是太差了,他只好写一些套路的水题了……

什么叫期望的逆推呢。。?

那就是对于现在的状态S,我们去考虑它的所有后继状态 T 1 , T 2 ⋯ T m {T_1,T_2\cdots T_m} T1,T2Tm,且各个后继发生的概率是 p 1 , p 2 ⋯ p m p_1,p_2\cdots p_m p1,p2pm和它们分别的转移代价 c 1 , c 2 ⋯ c m c_1,c_2\cdots c_m c1,c2cm,那么就有 E ( S ) = ∑ i = 1 m ( E ( T i ) + c i ) p i E(S)=\sum_{i=1}^m (E(T_i)+c_i)p_i E(S)=i=1m(E(Ti)+ci)pi

比如我们来看个简单的例子,问一个正常的硬币期望抛多少次可以得到正面?我们设这个答案为x,那么 x = 0.5 ∗ ( 0 + 1 ) + 0.5 ( x + 1 ) x=0.5*(0+1)+0.5(x+1) x=0.5(0+1)+0.5(x+1),解方程可以得到 x = 2 x=2 x=2

那么我们来看这道题,其实是两个不同的问题。


对于第一个问题,我们设 f [ i ] f[i] f[i]表示已经有i个连续相同的数字,离达到连续n个期望多少次。则有

f [ i ] = 1 m f [ i + 1 ] + m − 1 m f [ 1 ] + 1 f[i]=\frac 1 m f[i+1]+\frac {m-1} m f[1]+1 f[i]=m1f[i+1]+mm1f[1]+1

~~按照套路,~~作差可得 m ( f [ i + 1 ] − f [ i ] ) = f [ i + 2 ] − f [ i + 1 ] m(f[i+1]-f[i])=f[i+2]-f[i+1] m(f[i+1]f[i])=f[i+2]f[i+1]

然后我们又有 f [ 0 ] − f [ 1 ] = 1 , f [ n ] = 0 f[0]-f[1]=1,f[n]=0 f[0]f[1]=1,f[n]=0,上等比数列求和公式 a n s = f [ 0 ] = m n − 1 m − 1 ans=f[0]=\frac {m^n-1} {m-1} ans=f[0]=m1mn1


对于第二个问题,设 f [ i ] f[i] f[i]表示已经有i个连续不相同的数字,离达到连续n个期望多少次。

f [ i ] = m − i m f [ i + 1 ] + ∑ j = 1 i f [ j ] m f[i]=\frac {m-i} m f[i+1]+\frac {\sum_{j=1}^i f[j]} {m} f[i]=mmif[i+1]+mj=1if[j]

我们又作差

f [ i ] − f [ i + 1 ] = m − i − 1 m ( f [ i + 1 ] − f [ i + 2 ] ) f[i]-f[i+1]=\frac {m-i-1} m(f[i+1]-f[i+2]) f[i]f[i+1]=mmi1(f[i+1]f[i+2])

不会用求和公式了,直接暴力 O ( n ) O(n) O(n)搞一搞就行了。

顺带一提,这个数据不知为什么用read会TLE,改成scanf就可以了。

Code

#include <cstdio>
#include <cmath>
#define rg register
using namespace std;
typedef long long ll;
template <typename Tp> inline int getmin(Tp &x,Tp y){return y<x?x=y,1:0;}
template <typename Tp> inline int getmax(Tp &x,Tp y){return y>x?x=y,1:0;}
template <typename Tp> inline void read(Tp &x)
{
	x=0;int f=0;char ch=getchar();
	while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
	if(ch=='-') f=1,ch=getchar();
	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	if(f) x=-x;
}
int z,m,n,op;
double ans,tmp;
int main()
{
	#ifndef ONLINE_JUDGE
	freopen("in.txt","r",stdin);
	#endif
	while(~scanf("%d",&z))
	{
		while(z--)
		{
			scanf("%d%d%d",&op,&m,&n);
			if(!op) ans=(pow(m,n)-1.0)/(m-1.0);
			else
			{
				tmp=1.0;ans=0.0;
				for(rg int i=0;i<n;i++) tmp*=1.0*m/(m-i),ans+=tmp;
			}
			printf("%.9lf\n",ans);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值