P6944 [ICPC 2018 WF] Gem Island 题解
记 \(a_i\) 表示 \(d\) 天后第 \(i\) 个人拥有的宝石数,则确定每天被选择的人的方案数为 \(\frac{d!}{\prod_{i=1}^n (a_i-1)!}\),确定宝石分裂顺序的方案数为 \(\prod_{i=1}^n(a_i-1)!\),可以发现得到任意一种 \(a\) 序列的方案数都为 \(d!\)。
接下来考虑 dp,记 \(g_{S,i}\) 表示当前所有数的和为 \(S\),最大值有 \(i\) 个的方案数,\(f_{S,i}\) 表示 \(r\) 个最大值的和,直接转移即可:
\[g_{S,i}=\sum_{j=i}^n {j\choose i}g_{S-j,j}\\
f_{S,i}=\sum_{j=i}^n {j\choose i}(f_{S-j,j}+g_{S-j,j}\min(r,i))\\
\]
时间复杂度 \(\mathcal O(dn^2)\)。
参考代码:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define rept(i,a,b) for(int i=(a);i<(b);++i)
#define drep(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
int n,d,r;
double s1,s2,f[503][503],g[503][503],c[503][503];
signed main(){
cin>>n>>d>>r;
c[0][0]=1;
rep(i,1,n){
c[i][0]=1;
rep(j,1,i)c[i][j]=c[i-1][j-1]+c[i-1][j];
}
g[0][n]=1;
rept(s,0,d){
drep(i,n,1){
rep(k,1,i){
if(s+k>d)break;
g[s+k][k]+=g[s][i]*c[i][k];
f[s+k][k]+=(f[s][i]+g[s][i]*min(r,k))*c[i][k];
}
}
}
rep(i,1,n)s1+=g[d][i],s2+=f[d][i];
printf("%.10lf",s2/s1+r);
return 0;
}

浙公网安备 33010602011771号