题目链接
题目描述
一道选择题有四个选项,有 n n n 个人来做这题,第 i i i 个人有 p i , j p_{i,j} pi,j 的概率选第 j j j 个选项。定义 c n t x cnt_x cntx为选第 x x x 个选项的人数。令 m x mx mx 为 c n t x cnt_x cntx 最大的 x x x ( ( (如果有多个最大 c n t x cnt_x cntx 的 x x x,则取其中 x x x 最小的),若 c n t m x ≤ ⌊ n 2 ⌋ cnt_{mx}\le\lfloor\frac{n}{2}\rfloor cntmx≤⌊2n⌋,则所有人得 0 0 0 分;否则令 c h o i c e i choice_i choicei 表示第 i i i 个人选的选项,则第 i i i 人得 w m x , c h o i c e i w_{mx,choice_i} wmx,choicei 分。求每个人的期望得分。 n ≤ 2000 n\le 2000 n≤2000。
解题思路
由于题目中说明 c n t m x ≤ ⌊ n 2 ⌋ cnt_{mx}\le \lfloor\frac{n}{2}\rfloor cntmx≤⌊2n⌋ 是没有得分的,在期望的角度上可以看作这种情况没有贡献。那么,有贡献的当且仅当有 m x mx mx 使得 c n t m x > ⌊ n 2 ⌋ cnt_{mx} > \lfloor\frac{n}{2}\rfloor cntmx>⌊2n⌋,所以我们考虑枚举 m x mx mx。
令 t ( t ← 1 ∼ 4 ) t\ (t \leftarrow 1\sim4) t (t←1∼4) 为当前选择的人数最多的选项,考虑 dp \text{dp} dp。
令
f
i
,
j
f_{i,j}
fi,j 表示前
i
i
i 个人,
j
j
j 个人选择了
t
t
t 这个选项的概率,那我们分两种情况转移:
f
i
,
j
=
{
f
i
−
1
,
j
×
(
1
−
p
i
,
t
)
→
第
i
个
人
不
选
t
选
项
f
i
−
1
,
j
−
1
×
p
i
,
t
→
第
i
个
人
选
t
选
项
f_{i,j}=\begin{cases}f_{i-1,j}\times(1-p_{i,t})\rightarrow 第i个人不选t选项\\f_{i-1,j-1}\times p_{i,t}\rightarrow 第i个人选t选项\end{cases}
fi,j={fi−1,j×(1−pi,t)→第i个人不选t选项fi−1,j−1×pi,t→第i个人选t选项
设计好这个
dp
\text{dp}
dp 状态后感觉有点无从下手,这个
dp
\text{dp}
dp 不能算出方案和每个人得分的期望。考虑对每个第
i
i
i 个人枚举他所选的选项
k
k
k,根据选择人数最多的
t
t
t 选项和
dp
\text{dp}
dp 数组
f
f
f,可以推出前
i
i
i 个,但是对于后面的选择方案还是难处理,所以再引入一个
g
g
g 数组,去
dp
\text{dp}
dp 出后面的概率。
首先令
g
i
,
j
g_{i,j}
gi,j 表示第
i
∼
n
i\sim n
i∼n 人,
j
j
j 个人选择了
t
t
t 这个选项的概率,也分两种情况转移:
g
i
,
j
=
{
g
i
+
1
,
j
×
(
1
−
p
i
,
t
)
→
第
i
个
人
不
选
t
选
项
g
i
+
1
,
j
−
1
×
p
i
,
t
→
第
i
个
人
选
t
选
项
g_{i,j}=\begin{cases}g_{i+1,j}\times (1-p_{i,t})\rightarrow 第i个人不选t选项\\g_{i+1,j-1}\times p_{i,t}\rightarrow 第i个人选t选项\end{cases}
gi,j={gi+1,j×(1−pi,t)→第i个人不选t选项gi+1,j−1×pi,t→第i个人选t选项
由于题目里要求是
>
⌊
n
2
⌋
>\lfloor\frac{n}{2}\rfloor
>⌊2n⌋,所以假如去枚举
⌊
n
2
⌋
+
1
∼
n
\lfloor\frac{n}{2}\rfloor+1\sim n
⌊2n⌋+1∼n 的每个
j
j
j,叠加
g
i
,
j
g_{i,j}
gi,j,显然会超时,那么我们只需要做后缀和,将
dp
\text{dp}
dp 数组
g
g
g 的含义改为:第
i
∼
n
i\sim n
i∼n 人,
≥
j
\ge j
≥j 个人选择了
t
t
t 这个选项的概率。只需要
g
i
,
j
=
g
i
,
j
+
g
i
,
j
+
1
g_{i,j}=g_{i,j}+g_{i,j+1}
gi,j=gi,j+gi,j+1 就可以了。
算出 f , g f,g f,g 后, O ( 4 n 2 ) O(4n^2) O(4n2) 枚举,考虑到第 i i i 个人,前 i − 1 i-1 i−1 个人中 j j j 个选择了 t t t 这个选项,当前人选择的选项,对第 i i i 人得分的贡献 ( i (i (i枚举当前考虑到的人, j j j枚举 i i i前面的人中 j j j个选择 t t t选项, k k k枚举当前第 i i i人的选项 ) ) ): f i − 1 , j × p i , k × w t , k × g i + 1 , max ( 0 , ⌊ n 2 ⌋ + 1 − [ t = = k ] ) f_{i-1,j}\times p_{i,k}\times w_{t,k}\times g_{i+1,\max(0,\lfloor\frac{n}{2}\rfloor+1-[t==k])} fi−1,j×pi,k×wt,k×gi+1,max(0,⌊2n⌋+1−[t==k])。表示前 i − 1 i-1 i−1 人 j j j 人选择 t t t 的概率 × \times ×当前第 i i i 人选择 k k k 的概率 × \times ×当前情况的得分贡献 × \times ×想要使得 c n t m x > ⌊ n 2 ⌋ cnt_{mx}>\lfloor\frac{n}{2}\rfloor cntmx>⌊2n⌋ 后 i + 1 ∼ n i+1\sim n i+1∼n 的合法钦定选项方案的概率。总时间复杂度 O ( 16 n 2 ) O(16n^2) O(16n2)。
代码实现
#include<bits/stdc++.h>
#define For(i,a,b)for(int i=a;i<=b;i++)
#define Forr(i,a,b)for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int N=2005,mod=998244353;
int n,H;ll A[N],a[N][5],b[5][5],f[N][N],g[N][N];
inline int read(){
char c=getchar();int x=0,f=1;
while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
return x*f;
}
int main(){
n=read();For(i,1,n)For(j,1,4)a[i][j]=read();For(i,1,4)For(j,1,4)b[i][j]=read();f[0][0]=g[n+1][0]=1,H=(n>>1)+1;
For(t,1,4){
For(i,1,n)For(j,0,i)f[i][j]=(1ll*f[i-1][j]*(1-a[i][t]+mod)%mod+(j>0)*1LL*a[i][t]*f[i-1][j-1]%mod)%mod;
Forr(i,n,1)For(j,0,n-i+1)g[i][j]=(1ll*g[i+1][j]*(1-a[i][t]+mod)%mod+(j>0)*1ll*a[i][t]*g[i+1][j-1]%mod)%mod;
For(i,1,n)Forr(j,n-i,0)g[i][j]=(g[i][j]+g[i][j+1])%mod;
For(i,1,n)For(j,0,i-1)For(k,1,4)A[i]=(A[i]+1ll*f[i-1][j]*a[i][k]%mod*b[t][k]%mod*g[i+1][max(0,H-j-(t==k))]%mod)%mod;
}
For(i,1,n)printf("%lld\n",A[i]);return 0;
}