DTOJ #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,p_1,p_2$。

【输出格式】

输出文件只有一行,一个整数表示答案。

【样例】

样例输入
输入样例1
1 2 2 1
输入样例2
3 6 8 4

样例输出
输出样例1
499122177
输出样例2
768511825

【数据范围与提示】

对于 $ 10 \% $ 的数据, $ l_1=l_2=0 $ 。

对于另外 $ 10 \% $ 的数据, $ l_1=0,l_2=1 $ 。

对于另外 $ 10 \% $ 的数据, $ l_1=1,l_2=0 $ 。

对于另外 $ 10 \% $ 的数据, $ l_1=l_2=1 $ 。

对于所有数据满足 $ 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$ 个第二种盒子的概率。显然 $f[i][j]$ 可从 $f[i-1][j],f[i][j-1],f[i-1][j-1],f[i][j]$ 转移得来。发现式子左右两端都有 $f[i][j]$,解个方程即可得到转移式。

初始值 $f[0][0]=1$,答案 $f[l1][l2]$。具体转移参见代码。

【代码】

 1 #include<bits/stdc++.h>
 2 inline int read ( void )
 3 {
 4     int x=0;char ch;bool f=true;
 5     while ( !isdigit(ch=getchar()) ) if ( ch=='-' ) f=false;
 6     for ( x=ch^48;isdigit(ch=getchar()); ) x=(x<<1)+(x<<3)+(ch^48);
 7     return f ? x : -x ;
 8 }
 9 const int mod=998244353;
10 inline int power ( int a,int b )
11 {
12     int res=1;
13     for ( ;b;b>>=1,a=1LL*a*a%mod ) if ( b&1 ) res=1LL*res*a%mod;
14     return res;
15 }
16 int f[2010][2010];
17 inline void Add ( int &x,int y ) { x+=y;x-=(x>=mod)?mod:0; }
18 signed main()
19 {
20     int l1=read(),l2=read(),p1=read(),p2=read();
21     if ( !l2 ) return !puts("0");
22     if ( !l1 ) return !puts("1");
23     int invp1=power(p1,mod-2),invp2=power(p2,mod-2);
24     int q1=(1-invp1+mod)%mod,q2=(1-invp2+mod)%mod;
25     f[0][0]=1;
26     int res=power((1-1LL*q1*q2%mod+mod)%mod,mod-2);
27     for ( int i=0;i<l1;i++ ) for ( int j=0;j<l2;j++ )
28         Add(f[i+1][j],1LL*f[i][j]*res%mod*invp1%mod*q2%mod),
29         Add(f[i][j+1],1LL*f[i][j]*res%mod*invp2%mod*q1%mod),
30         Add(f[i+1][j+1],1LL*f[i][j]*res%mod*invp1%mod*invp2%mod);
31     int ans=0;
32     for ( int i=0;i<l2;i++ ) Add(ans,f[l1][i]);
33     return !printf("%d\n",ans);
34 }

 

posted @ 2019-08-09 15:01  DTOI_RSY  阅读(182)  评论(0编辑  收藏  举报