牛客网NOIP赛前集训营-提高组(第六场)B-选择题

题目描述

有一道选择题,有 a,b,c,d 四个选项。

现在有 n 个人来做这题,第 i 个人有 pi,j 的概率选第 j 个选项。

定义\(cnt(x)\)为选第$ x $个选项的人数。

\(mx\)\(cnt(x)\)最大的\(x\)(如果有多个\(cnt(x)\)最大的$ x$,则取其中 \(x\) 最小的),若 img ,则所有人得 \(0\) 分;否则令 choicei 表示第$ i $个人选的选项,则第 i 人得 img 分。

求每个人的期望得分。

输入描述:

第一行一个整数 n ,表示人数。

接下来 n 行,每行 4 个整数,其中第 \(i\) 行第 \(j\) 个数表示 \(p_{i,j}\) ,即在模 \(998244353\) 意义下第 i 个人选第 j 个选项的概率。

接下来 4 行,每行 4 个整数,第 \(i\) 行第 \(j\) 个数表示 \(w_{i,j}\)

输出描述:

共 n 行,第 i 行表示第 i 个人在模 \(998244353\) 意义下的期望得分。

示例1

输入

2
499122177 499122177 0 0
332748118 665496236 0 0
1 2 3 4
5 6 7 8 
9 10 11 12
13 14 15 16

输出

166374061
166374061

说明

第一个人选第 1,2,3,4 个选项的概率分别为 \frac{1}{2},\frac{1}{2},0,0

第二个人选第 1,2,3,4 个选项的概率分别为 \frac{1}{3},\frac{2}{3},0,0

当他们选择不同选项时,cnt(mx)=1 \le \lfloor \frac{2}{2} \rfloor=1 ,所有人得分为 \(0\)

当他们都选第 1 个选项时,概率为 (1/2)*(1/3)=1/6,两个人的得分都是 \(w_{1,1}=1\)

当他们都选第 2 个选项时,概率为 \frac{1}{2}\times\frac{2}{3}=\frac{1}{3} ,两个人的得分都是 \(w_{2,2}=6\)

所以两个人的期望得分都是 \frac{1}{6} \times 1 + \frac{1}{3} \times 6=\frac{13}{6} , 模 \(998244353=166374061\)

Solution

首先循环枚举每个选项\(a\)

我们设\(f[i][j]\)表示前\(i\)个人有\(j\)人选了这个选项的概率,\(g[i][j]\)表示后\(i\)个人有\(j\)人选了这个选项的概率。转移是很显然的吧。

\[f[i][j]=f[i-1][j-1]\times p[i][a]+f[i-1][j]\times (1-p[i][a])\quad f[0][0]=1 \]

\[g[i][j]=g[i+1][j-1]\times p[i][a]+g[i+1][j]\times (1-p[i][a])\quad g[n+1][0]=1 \]

然后我们考虑对\(g\)的第二维做个后缀和或者对\(f\) 的第二维做个前缀和。我们拿做\(g\)来说。那么\(g[i][j]\)的意义就变成了后\(i\)个人,选了这个选项的人数不少于\(j\)个的概率。

然后枚举每一个人,对每一个人,再枚举这个人前面有多少人选这一项,然后下面就不用再说了吧,非常显然的搞一下就好了。

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
#define lowbit(x) ((x)&(-(x)))
#define REP(i,a,n) for(register int i=(a);i<=(n);++i)
#define PER(i,a,n) for(register int i=(a);i>=(n);--i)
#define FEC(i,x) for(register int i=head[x];i;i=g[i].ne)
template<typename A>inline void read(A&a){a=0;char c=0;int f=1;while(c<'0'||c>'9')(c=getchar())=='-'?f=-1:0;while(c>='0'&&c<='9')a=(a<<3)+(a<<1)+c-'0',c=getchar();f==-1?a=-a:0;}
char buf[30];template<typename A>inline void write(A a){if(a<0)putchar('-'),a=-a;int top=0;if(!a)buf[top=1]='0';while(a)buf[++top]=a%10+'0',a/=10;while(top)putchar(buf[top--]);}
typedef long long ll;typedef unsigned long long ull;
template<typename A,typename B>inline bool SMAX(A&x,const B&y){return y>x?x=y,1:0;}
template<typename A,typename B>inline bool SMIN(A&x,const B&y){return y<x?x=y,1:0;}

const int N=2000+7,MOD=998244353;
int n,m,p[N][4],w[4][4],f[N][N],g[N][N],ans[N];
template<typename A,typename B>inline void SADD(A&x,const B&y){x+=y;x>=MOD?x-=MOD:0;}

int main(){
	read(n);m=(n>>1)+1;
	for(register int i=1;i<=n;++i)read(p[i][0]),read(p[i][1]),read(p[i][2]),read(p[i][3]);
	for(register int i=0;i<4;++i)read(w[i][0]),read(w[i][1]),read(w[i][2]),read(w[i][3]);
	for(register int c=0;c<4;++c){
		memset(f,0,sizeof(f));memset(g,0,sizeof(g));f[0][0]=1;g[n+1][0]=1;
		for(register int i=1;i<=n;++i)
			for(register int j=0;j<=i;++j)f[i][j]=((j?(ll)f[i-1][j-1]*p[i][c]%MOD:0)+(ll)f[i-1][j]*(MOD+1-p[i][c])%MOD)%MOD;
		for(register int i=n;i;--i)
			for(register int j=0;j<=n-i+1;++j)g[i][j]=((j?(ll)g[i+1][j-1]*p[i][c]%MOD:0)+(ll)g[i+1][j]*(MOD+1-p[i][c])%MOD)%MOD;
		for(register int i=1;i<=n;++i)
			for(register int j=n-i;~j;--j)SADD(g[i][j],g[i][j+1]);
		for(register int i=1;i<=n;++i){
			for(register int j=0;j<=i;++j)
				for(register int k=0;k<4;++k)SADD(ans[i],(ll)f[i-1][j]*g[i+1][m-j-(k==c)>=0?m-j-(k==c):0]%MOD*p[i][k]%MOD*w[c][k]%MOD);
		}
	}
	for(register int i=1;i<=n;++i)write(ans[i]),putchar('\n');
}
posted @ 2018-10-22 19:18  hankeke303  阅读(183)  评论(0编辑  收藏  举报