「ABC243F」Lottery 题解
「ABC243F」Lottery 题解
思路
设 \(p_i\) 为抽出第 \(i\) 个角色的概率,可以直接算出来。
然后直接动态规划,设 \(dp_{i,j,k}\) 为前 \(i\) 个角色,抽了 \(j\) 次奖,有 \(k\) 种不同角色的概率。
接下来我们考虑对于第 \(i\) 个角色,抽了 \(t\) 次都抽出来的概率。
发现抽这个角色 \(t\) 次的概率就是 \(p_i^t\)。
这 \(t\) 次可以是任意 \(t\) 次,所以需要再乘上一个 \(C_j^t\)。
可以通过 \(dp_{i-1,j-t,k-1}\) 转移过来。
然后就很容易得出状态转移式:
\[dp_{i,j,k}= dp_{i-1,j-t,k-1}\times C_j^t\times p_i^t
\]
最后答案为 \(dp_{n,K,m}\)。
注意组合数预处理到最大值 \(50\) 而不是 \(n\)。
具体细节看代码注释。
Code
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<map>
#include<set>
#include<vector>
#include<string>
#include<iostream>
#include<unordered_map>
#define int long long
#define inf 0x3f3f3f3f
#define il inline
#define db double
#define F(i,a,b) for(int i=(a);i<=(b);++i)
#define f(i,a,b) for(int i=(a);i>=(b);--i)
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
il int read(){int w=1,c=0;char ch=getchar();for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;for(;ch>='0'&&ch<='9';ch=getchar()) c=(c<<3)+(c<<1)+ch-48;return w*c;}
void printt(int x){if(x>9) printt(x/10);putchar(x%10+48);}
il void print(int x){if(x<0) putchar('-'),printt(-x);else printt(x);}
il void put(int x){print(x);putchar('\n');}
const int N=110;
const int mod=998244353;
int w[N];
int n,m,K,sum;
int dp[N][N][N];
int c[N][N];
void init()
{
F(i,0,50) F(j,0,i)//处理到50
{
if(!j) c[i][j]=1;
else c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
}
}
inline int qpow(int a,int b)//快速幂
{
int res=1;
while(b)
{
if(b&1)res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
inline int inv(int a){return qpow(a,mod-2)%mod;}//使用费马小定理求出逆元
signed main()
{
n=read(),m=read(),K=read();
F(i,1,n) w[i]=read(),sum+=w[i];
init();//预处理组合数
dp[0][0][0]=1;
F(i,1,n)
{
dp[i][0][0]=1;//初始化
F(j,1,K)
{
F(k,1,m)
{
dp[i][j][k]=dp[i-1][j][k];
F(t,1,j) dp[i][j][k]=(dp[i][j][k]+c[j][t]*dp[i-1][j-t][k-1]%mod*qpow(w[i]*inv(sum)%mod,t)%mod)%mod;
/*w[i]*inv(sum)即为p[i]*/
}
}
}
std::cout<<dp[n][K][m];
return 0;
}