P1291 [SHOI2002]百事世界杯之旅
题目描述
你关上电视,心想:假设有 \(n\) 个不同的球星名字,每个名字出现的概率相同,平均需要买几瓶饮料才能凑齐所有的名字呢?
期望dp 水题 (bushi)。但这输出也未免太毒瘤了吧。
设 \(f[i]\) 表示当前当前有 \(i\) 个球星的名字的期望。
我们有 \(i\over n\) 的概率抽到的是之前取到的,这时候我们就还需要再抽 \(f[i]\) 次,所以期望就是 \({i\over n}\times (f[i] + 1)\)
还有 \({n-i}\over i\) 的概率抽到的是之前没有取到的,这时候我们只需要再取 \(f[i-1]\) 次就可以,那么期望就是 \({{n-i}\over i} \times ({f[i-1] + 1})\)
然后我们就得到了递推式 \(f[i] = {i\over n}\times (f[i] + 1) + {{n-i}\over i} \times ({f[i-1] + 1})\)
化简一下可以得到: \(f[i] = f[i-1] + {n\over{n-i}}\)
转化一下形式变为 \(\displaystyle\sum_{i=1}^{n} {n\over{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\n",ans);
else
{
for(int i = 1; i <= wei(ans); i++) printf(" ");
printf("%lld\n",zi);
printf("%lld",ans);
for(int i = 1; i <= wei(mu); i++) printf("-");
printf("\n");
for(int i = 1; i <= wei(ans); i++) printf(" ");
printf("%lld\n",mu);
}
return 0;
}