HDU 4986 Little Pony and Alohomora Part I(递推+欧拉常数)

Little Pony and Alohomora Part I

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 365    Accepted Submission(s): 188


Problem Description
Trixie is a female unicorn pony and traveling magician, having been rumored to be "the most magical unicorn in all of Equestria". One day, Trixie arrives in Ponyville.


There is n boxes on the stage.  There is a random key in each box and each box has a key match it. As a unicorn, Trixie can use "Alohomora"(the unlocking spell) to open any box. 

Trixie would like to open all the boxes, also Trixie would like to minimize the spells she used. Help Trixie to calculate the expected number of spells she need to used in order to open all the boxes necessary.
 

Input
Input contains multiple test cases (less than 100). 
For each test case, only one line contains one integer n (1<=n<=1000000000).
 

Output
For each case, output the corresponding result, rounded to 4 digits after the decimal point.
 

Sample Input
  
  
1 2
 

Sample Output
  
  
1.0000 1.5000
Hint
The second sample: There are two different permutations when n equal to 2: (1, 2) and (2, 1). Trixie need to use 2 spells in (1, 2) and 1 spell in (2, 1).
 

Source
 


题目大意:有 n 个box盒子(从左到右编号依次为1~n),每个盒子里面随机放一把能打开某个盒子的钥匙,有可能这把钥匙恰好可以开到这个盒子,但大多数情况下是不可以的。问把所有的盒子都打开的期望值是多少。(例如对于两个盒子,有可能装着1 2 或者 2 1的钥匙,如果是1 2,那么就需要用两次咒语,而对于2 1(打开其中一个box就可以得到要开的另一个盒子的钥匙)只需要用一次即可。期望值就是 1/2 * 2 + 1/2 * 1 = 1.5 (1/2 是表示情况数)。



解题思路:题目意思相当于给出两个序列,第一个序列按照1,2,……,n-1,n的顺序排列。第二个序列按照是将这n个数随机排列,求序列的置换循环次数。假设f[n]为n个盒子的情况,则f[n+1]要么就是孤立最后多一个循环,要么就是插入中间,循环个数不变,对应的转移方程为f[n + 1] = (f[n] + 1) / n + f[n] * (n– 1) / n,化简得到f[n] = f[n - 1] + 1 / n。f[n]=1+1/2+1/3+……+1/n,就是调和级数的前i项和,而调和级数的近似公式是:ln(n)+r(其中r是欧拉常数,r=0.57721566490153286060651209)。当i比较小时,应该用递推公式计算,公式的精度不够;当n足够大时,直接用公式求解。


代码如下:

#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
#define MAX 6005
double f[MAX];

void get()
{
    ll i,j,k;
    f[1]=1.0;
    for(i=2;i<MAX;i++)
    {
        f[i]=f[i-1]+1.0/i;
    }
}
int main()
{
    ll n;
    get();
    while(~scanf("%I64d",&n))
    {
        if(n<MAX)
            printf("%.4f\n",f[n]);
        else//欧拉常数
            printf("%.4f\n",log(n)+0.57721);
    }
    return 0;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值