Codeforces

Luogu

分析

显然装备之间没有区别,我们只要计算一种装备的期望,然后乘上 $k$ 即可。

考虑倒推。设 $dp_{i,j}$ 表示剩余 $i$ 个怪物、装备等级为 $j$ 期望获得的金币数,转移有三种:

  • 选到了其它装备:概率为 $\frac{k-1}{k}$,期望收益为 $dp_{i-1,j}$。
  • 选到了等级为 $j+1$ 的当前装备:概率为 $\frac{1}{k(j+1)}$,期望收益为 $dp_{i-1,j+1}+j$。
  • 选到了等级为 $[1,j]$ 的当前装备:概率为 $\frac{j}{k(j+1)}$,期望收益为 $dp_{i-1,j}+\frac{j+1}{2}$。

这样子是 $\mathcal{O}(n^2)$ 的。注意到当装备等级很高时概率趋近于 $0$,所以我们可以只对前 $L$ 种等级 DP,复杂度 $\mathcal{O}(nL)$。计算得到期望等级大概是 $\mathcal{O}(\sqrt{\frac{n}{k}})$ 级别,所以我们可以令 $L=600$。

代码

// ====================================
//   author: M_sea
//   website: https://m-sea-blog.com/
// ====================================
#include <bits/stdc++.h>
#define file(x) freopen(#x".in","r",stdin),freopen(#x".out","w",stdout)
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef long long ll;

int read() {
    int X=0,w=1; char c=getchar();
    while (c<'0'||c>'9') { if (c=='-') w=-1; c=getchar(); }
    while (c>='0'&&c<='9') X=X*10+c-'0',c=getchar();
    return X*w;
}

const int N=100000+10,M=600+10;

int n,k;
double dp[2][M];

int main() {
    n=read(),k=read();
    for (int i=1;i<=n;++i) {
        int cur=i&1,pre=cur^1;
        for (int j=1;j<=600;++j) {
            dp[cur][j]=dp[pre][j]*(k-1)/k;
            dp[cur][j]+=(dp[pre][j+1]+j)/k/(j+1);
            dp[cur][j]+=(dp[pre][j]+(j+1)/2.0)/k*j/(j+1);
        }
    }
    printf("%.10lf\n",dp[n&1][1]*k);
    return 0;
}
最后修改:2020 年 11 月 21 日 04 : 34 PM