题目大意:n个箱子,每个箱子一把钥匙,随机放在一个箱子里,现在你要打开所有箱子,求要用开箱魔法(不用钥匙也能开箱子)的次数期望。
先不考虑过大的n尝试用 dp去解,
设有1,2,3...n
随机选取出一个箱子先开,这里假设选1,
1箱中有2种可能 1/n的可能 装着 钥匙1 这时 dp[i]=(dp[i-1]+1)/n。
第二种 n-1/n的可能 假设装着钥匙2 这时 2箱子已不能装钥匙2(因为被1选了)但1钥匙 和其他钥匙的选择导致的状态无法判断是否平等
所以把这状态写为f(1,n-2) 表示 2箱子可能装的钥匙 前者表示2箱子可以装的已经开过的箱子的钥匙数量 后者表示2箱子可以装的没开过箱子的钥匙数目
dp[i]=f(1,n-2)*(n-1)/n。
现在我们对f(1,n-2)进行分析,有选1时 状态f(1,n-2)=(dp[i-2]+1)/(n-1)。
选n-2时 假设选了3 这时箱子3 不可以选钥匙2 和钥匙3 只能是选钥匙1 或其他n-3个钥匙 有 f(1,n-2)= f(1,n-3)*(n-2)/(n-1)。
而这个f(1,n-2) 跟的d[i-1]的方程是一模一样的 ,所以有f(1,n-2)=d[i-1]。dp[i]=(dp[i-1]+1)/n+d[i-1]*(n-1)/n=d[i-1]+1/n。
所以 从1开始 不断增加 1/2、1/3、1/4等等。
当然你手推出3 和4 的情况 自己猜一下规律也猜的出来,可靠规律做这题就一点意义都没有了,你在百度下调和级数,这题就白做了。如果这种题都靠规律来做,等到真正难的题,没有规律了,你没有养成好的思考习惯,肯定是出不出来的。
现在前面的结论得出了,不管你是找规律还是推出来,都要面临一个新的问题,n太大了怎么处理,手推没有发现很好的公式,有人直接就去百度了,但这样不锻炼思维,等到比赛时没有百度怎么办呢? 所以我试着找规律 开始想他会不会后来就不涨了 打表后发现只是涨的缓慢,于是就开始跟根号n和log2 做差什么的,最后发现 和loge(n)的差值十分稳定,大概在0.57722左右,后来才知道这叫调和级数 欧拉发现的
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#include<stack>
#include<bitset>
#define inf 0x3f3f3f3f
#define ll long long
#define mod 1000000007
using namespace std;
#define bug puts("bugbugubgbugbug");
int main()
{
int n;
while(~scanf("%d",&n))
{
if(n>=1000000)
printf("%.4lf\n",log((double)n)+0.57722);
else{
double ans=0;
for(int i=1;i<=n;i++)
{
double j=i;
ans+=1/j;
}
printf("%.4lf\n",ans);
}
}
return 0;
}