ABC310F Make 10 Again 题解

· · 题解

分析

看到求概率,想到概率 dp。

为了方便,我们令以下运算都在模 998244353 的意义下进行,同时令二进制数的最低位为第 0 位。

我们先求这个概率的分母。第 i 个骰子正面朝上的可能是 1\sim a_i,共有 a_i 中可能,所以这个概率的分母为 a_1 \times a_2 \times a_3 \times \cdots \times a_N,即 \prod\limits_{i=1}^N a_i。我们令其等于 den

接下来我们求这个概率的分子。我们可以把“是否可以凑出 0,1,2\cdots,10” 都压进状态里,进行状压 dp。其中,对于状态 S,如果它在二进制表示下第 i 位为 0 则表示不能凑出 i,反之则表示可以凑出 i。容易发现有 0 \sim 2^{11}-12^{11} 种状态。为了方便表示,我们令 K=2^{11}

输出 num\times den^{-1} 即可。

代码

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=998244353,N=105,P=12,K=2048;
int ksm(int a,int b){
    int res=1;
    while(b){
        if(b&1) res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
int dp[N][1<<P],n,a[N],pro=1;
signed main(){
    int s;
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i],pro=pro*a[i]%mod;
    dp[0][1]=1;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=min(11ll,a[i]);j++){
            for(int k=0;k<K;k++){
                s=k;
                for(int p=0;p<=10;p++) if(k>>p&1) s=s|1<<(j+p);
                s=s%K;
                dp[i][s]=(dp[i][s]+dp[i-1][k])%mod;
            }
        }
        if(a[i]>10) for(int k=0;k<K;k++) dp[i][k]=(dp[i][k]+dp[i-1][k]*(a[i]-11))%mod;
    }
    int ans=0;
    for(int k=K/2;k<K;k++){
        ans=ans+dp[n][k];
        ans%=mod;
    }
    cout<<(ans*ksm(pro,mod-2))%mod;
    return 0;
}