P1291 [SHOI2002]百事世界杯之旅

题目描述

Link

你关上电视,心想:假设有 (n) 个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢?


期望dp 水题 (bushi)。但这输出也未免太毒瘤了吧。

(f[i]) 表示当前当前有 (i) 个球星的名字的期望。

我们有 (iover n) 的概率抽到的是之前取到的,这时候我们就还需要再抽 (f[i]) 次,所以期望就是 ({iover n} imes (f[i] + 1))

还有 ({n-i}over i) 的概率抽到的是之前没有取到的,这时候我们只需要再取 (f[i-1]) 次就可以,那么期望就是 ({{n-i}over i} imes ({f[i-1] + 1}))

然后我们就得到了递推式 (f[i] = {iover n} imes (f[i] + 1) + {{n-i}over i} imes ({f[i-1] + 1}))

化简一下可以得到: (f[i] = f[i-1] + {nover{n-i}})

转化一下形式变为 (displaystylesum_{i=1}^{n} {nover{n-i}})

然后在求的的时候注意通分一下就行。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define int long long
int n,mu,zi,ans;
int gcd(int a,int b)
{
	if(b == 0) return a;
	else return gcd(b,a%b);
}
int wei(int x)
{
	int res = 0;
	while(x)
	{
		res++;
		x /= 10;
	}
	return res;
}
signed main()
{
	scanf("%lld",&n);
	mu = 1, zi = n;
	for(int i = 2; i <= n; i++)
	{
		zi = zi * i + n * mu;//通分
		mu = mu * i;
		int res = gcd(mu,zi);
		mu /= res;
		zi /= res;
	}
	int ans = zi / mu;//求带数
	zi %= mu;
	if(zi == 0) printf("%lld
",ans);
	else
	{
		for(int i = 1; i <= wei(ans); i++) printf(" ");
		printf("%lld
",zi);
		printf("%lld",ans);
		for(int i = 1; i <= wei(mu); i++) printf("-");
		printf("
");
		for(int i = 1; i <= wei(ans); i++) printf(" ");
		printf("%lld
",mu);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/genshy/p/13852507.html