HDU4652 Dice

这个题的正解是 \(O(n)\) 一次询问的, 主要用到的技巧是数列操作的技巧。

type 0

使用期望 dp, 设 f[i] 表示末尾已有 i 个相同的, 停止所需的期望次数, 所求即为 f[0]。

\[\begin{align} f[0] &= 1 +f[1] \tag{1} \\ f[i] &= 1 + \frac 1mf[i+1] + \frac{m-1}{m}f[1] \tag{2} \\ f[i+1] &= 1 + \frac 1mf[i+2] + \frac{m-1}{m}f[1] \tag{3} \\ f[n] &= 0\tag{4} \end{align} \]

\((2)-(3)\) 得:

\[m*(f[i]-f[i+1]) =f[i+1]-f[i+2] \]

注意到这是个递推式, 设 \(f'[i] = f[i]-f[i+1]\), 那么 \(f[0] = \sum\limits_{i=0}^{n-1} f'[i]\)(由于 \(f[n]=0\))。

显然 \(f'[0]=1\),于是就可以递推了。

type 1

还是使用期望 dp, 设 f[i] 表示末尾已有 i 个两两不同的, 停止所需的期望次数, 所求还是 f[0]。

\[\begin{align} f[0] &= 1+f[1]\tag{1} \\ f[i] &= 1 + \frac{m-i}{m} f[i+1] + \frac 1m \left( f[1]+f[2]+\cdots +f[i] \right)\tag{2} \\ f[i+1] &= 1 + \frac{m-i-1}{m} f[i+2] + \frac 1m \left( f[1]+f[2]+\cdots +f[i+1] \right)\tag{3} \\ f[n] &= 0\tag{4} \end{align} \]

还是 \((2)-(3)\) 得:

\[\begin{align} f[i] - f[i+1] &= \frac{m-i}mf[i+1] - \frac{m-i-1}mf[i+2] - \frac 1mf[i+1] \\ m*f[i] - m*f[i+1] &= (m-i)*f[i+1] - (m-i-1)*f[i+2] - f[i+1] \\ m*f[i] - m*f[i+1] &= (m-i-1)*f[i+1] - (m-i-1)*f[i+2] \\ m*(f[i]-f[i+1]) &= (m-i-1)*(f[i+1]-f[i+2]) \end{align} \]

又是个递推式, 设 \(f'[i] = f[i]-f[i+1]\), 依然有 \(f[0] = \sum\limits_{i=0}^{n-1} f'[i]\)

显然 \(f[0]=1\), 依然可以递推。

code

hduOJ 厌 getchar type 快读好震撼啊。

#include<cstdio>
#define gc() getchar()
using namespace std;

double calc0(int n,int m)
{
	double res = 1,  f = 1;
	for(int i=1;i<n;++i)
	{
		f = f * m;
		res += f;
	}
	return res;
}

double calc1(int n,int m)
{
	double res = 1,  f = 1;
	for(int i=1;i<n;++i)
	{
		f = f * m / (m-i);
		res += f;
	}
	return res;
}

int main()
{
//	cout << calc0(5,6);
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int op,n,m;
		scanf("%d%d%d",&op,&m,&n);
		if(op==0)
			printf("%.9lf\n", calc0(n,m));
		else
			printf("%.9lf\n", calc1(n,m));		
	}
	return 0;
}
posted @ 2020-11-28 18:46  xwmwr  阅读(49)  评论(0编辑  收藏  举报