D. Jon and Orbs(概率dp)

D. Jon and Orbs
time limit per test
2 seconds
memory limit per test
256 megabytes
input
standard input
output
standard output

Jon Snow is on the lookout for some orbs required to defeat the white walkers. There are k different types of orbs and he needs at least one of each. One orb spawns daily at the base of a Weirwood tree north of the wall. The probability of this orb being of any kind is equal. As the north of wall is full of dangers, he wants to know the minimum number of days he should wait before sending a ranger to collect the orbs such that the probability of him getting at least one of each kind of orb is at least , where ε < 10 - 7.

To better prepare himself, he wants to know the answer for q different values of pi. Since he is busy designing the battle strategy with Sam, he asks you for your help.

Input

First line consists of two space separated integers kq (1 ≤ k, q ≤ 1000) — number of different kinds of orbs and number of queries respectively.

Each of the next q lines contain a single integer pi (1 ≤ pi ≤ 1000) — i-th query.

Output

Output q lines. On i-th of them output single integer — answer for i-th query.

Examples
input
1 1
1
output
1
input
2 2
1
2
output
2
2

题意:

琼恩要派遣游骑兵去鬼影森林获取龙晶,共有k种龙晶,鬼影森林每天产生一种龙晶,由于长城以北过于危险,所有琼恩想知道让每种龙晶都至少有一件的概率大于p/2000至少需要多少天.共有q次询问,琼恩忙于和山姆讨论战术,这些问题就交给你啦.


解题思路:

概率题不会啊,QAQ,好不容想懂了题意,但是不会.

不能理解题意的同学可以考虑,因为每天可能产生之前出现过的龙晶种类,所以即使k天也不可能产生k种龙晶,而小于k天是肯定不能产生k种龙晶的.

如果去模拟计算各种不同情况的话,由于情况数太多是肯定会炸的.好在题目要求我们求的是概率,所以我们只需要去求概率就行.

我们考虑每天有两种情况,

第一种情况:鬼影森林产生了之前出现过的龙晶,这种概率就是j/k(j为已经出现的龙晶种类)

第二种情况:鬼影森林产生了之前没出现过的龙晶,这种概率是(k-j+1)/k

我们设dp[i][j]为第i天时已经产生j种龙晶,那么转移方程就是 dp[i][j]=dp[i-1][j]*j/k + dp[i-1][j-1]*(k-j+1)/k;

开二维数组,我们可以用滚动来 减少一维,但是强行开二维也是能过的.

由于有多次询问,我们每次都去跑dp的话肯定是要超时的,这里1<p<1000,我们预处理把1<p<1000的所有情况都先求出来,就能不超时了.


另外 琼恩粉感觉这场比赛很亲切啊!

代码:

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e3+7;
const double eps=1e-7;
int k,q;
int ans[MAXN];
double dp[MAXN];
void init()//尽量的把除转换成乘,防止精度损失
{
    dp[0]=1.0;
    for(int i=1,p=1;p<=1000;++i)
    {
        for(int j=k;j>0;--j)
        {
            dp[j]=(dp[j]*j+dp[j-1]*(k-j+1))/k;
        }
        while(p<=1000&&dp[k]*2000.0>=(p-eps))
        {
            ans[p]=i;
            p++;
        }
        dp[0]=0;
    }
}
int main()
{
    scanf("%d%d",&k,&q);
    int x;
    init();
    while(q--)
    {
        scanf("%d",&x);
        printf("%d\n",ans[x]);
    }
   return 0;
}










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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值