#3328. 开箱子(unboxing)
题目描述
开箱子是守望先锋中一项重要的活动, 50 箱多少金决定了你到底是欧皇还是部落酋长。
现在我们假设有两种箱子,一种是你升级得的,另一种是氪金的,分别有一个参数 p_1,p_2,你有 \frac{1}{p}(1- \frac{1}{p})^{k-1}的概率在得到箱子的 k 秒后开箱,注意箱子是一个一个给你的,也就是说上一个箱子开完后下一个箱子才会开始算时间。
现在有 l_1 个升级得到的箱子, l_2个氪金得到的箱子,两种箱子的第一个箱子是同时间给你的,告诉你 p_1,p_2,问你升级得到的箱子开完的时间严格小于氪金的箱子开完的时间的概率,为了避免精度问题,输出对 998244353 取模。
数据范围
对于所有数据满足 l_1,l_2 \in [0,2 \times 10^3],p_1,p_2 \in [1,10^9] ,我们规定 0^0=1 。
题解
挺简单的一道题考场想歪了哭辽
考虑 dp , f_{i,j} 表示升级箱开了 i 个,氪金箱开了 j 个的概率
考虑主动转移,如果升级箱开了第 i+1 个,则可以列出转移式子:
f_{i+1,j}+=f_{i,j} \times \frac{1}{p_1} \times (1-\frac{1}{p_2}) \times (\frac{1}{1-(1-\frac{1}{p_1})\times(1-\frac{1}{p_2})})
最后这个是中途没有人选的概率
剩下的转移类似,注意到i=n或者j=m的时候不能转移、
效率: O(l_1 \times l_2)
代码
#include <bits/stdc++.h> using namespace std; const int P=998244353,N=2005; int n,m,p,q,f[N][N],s,w; int K(int x){ int z=1; for (int y=P-2;y;y>>=1,x=1ll*x*x%P) if (y&1) z=1ll*z*x%P; return z; } int main(){ cin>>n>>m>>p>>q;f[0][0]=1; p=K(p);q=K(q);w=K(1-1ll*(1-p)*(1-q)%P); for (int i=0;i<n;i++) for (int j=0;j<m;j++){ (f[i+1][j]+=1ll*f[i][j]*p%P*(1-q)%P*w%P)%=P; (f[i][j+1]+=1ll*f[i][j]*q%P*(1-p)%P*w%P)%=P; (f[i+1][j+1]+=1ll*f[i][j]*p%P*q%P*w%P)%=P; } for (int j=0;j<m;j++) (s+=f[n][j])%=P; return printf("%d\n",(s+P)%P),0; }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步