首先,投一个骰子,每个数字出现的概率都是一样的。也就是不算小A的话,n个人投出x个骰子需要的次数和点数无关。
计数问题考虑dp,令f(i,j)为前i个人投j个同点数的骰子的方案数,容易得f(i,j)=sum{f(i-1,j-k)*f(1,k) | 0<=k<=m}.
边界是f(1,j),具体是什么值呢?一个人投m个骰子,会得到6种点数,其中一种有j个,其他的五种有m-j个。也就是把m-j个骰子分成5份的方案数。
用插板法可得f(1,j)=C(m-j+4,4)=(m-j+1)(m-j+2)(m-j+3)(m-j+4)/24.
然后好像说这玩意可以用FFT优化,真成NOI Plus模拟赛了……
#include <iostream> #define maxn 405 using namespace std; typedef unsigned long long ullint; const ullint c=998244353; int n,m,x,y; ullint dp[maxn][maxn*maxn]; int main() { ios::sync_with_stdio(false); cin>>n>>m>>x>>y; int cnt=0,tmp; for(int i=1;i<=m;i++) { cin>>tmp; if(tmp==y) cnt++; } for(int j=0;j<=m;j++) dp[1][j]=(m-j+1)%c*(m-j+2)%c*(m-j+3)%c*(m-j+4)%c*291154603%c; for(int i=2;i<=n;i++) for(int j=0;j<=i*m;j++) for(int k=0;k<=min(j,m);k++) dp[i][j]=(dp[i][j]+dp[i-1][j-k]*dp[1][k]%c)%c; ullint ans=0; for(int j=x-cnt;j<=n*m;j++) ans=(ans+dp[n][j])%c; cout<<ans<<endl; return 0; }
时间: 2024-10-04 19:38:21