@description@

一个随机数发生器会生成 N 种数。

第 i 种数有参数 Ai,记 SA = ∑Ai,随机数发生器会有 Ai/SA 的概率生成 i。

每个时刻都会生成一个数,直到某时刻对于所有的 i,第 i 种数被生成的次数 >= Bi 停止。

求停止的期望时刻。

Constraints

1 <= Ai,Bi,N,∑Ai, ∑Bi <= 400。

Input

输入形式如下:

N

A0 B0

A1 B1



AN−1 BN−1

Output

输出期望时刻 mod 998244353。

Sample Input 1

2

1 1

1 1

Sample Output 1

3

@solution - 1@

先对问题进行初步的转化:

假如在第 t 时刻停止,贡献为 t。

我们可以将 t 的贡献看成第 0 时刻没有停止贡献 1,第 1 时刻没有停止贡献 1,…,第 t-1 时刻没有停止贡献 1,总共贡献 t。

记 p(i) 表示第 i 时刻依然没有停止的概率,则有停止的期望时刻为 \(\sum_{i=0}p(i)\)。

考虑怎么求 p(i)。

假如给定一个生成的序列 x1, x2, …, xi 表示第 j 时刻生成 xj,则得到该序列的概率应为 A[x1]/SA*A[x2]/SA*…*A[xi]/SA。

一种思路是对于所有长度为 i 的未停止序列计算概率之和,但不好做(但可以做)。

我们逆向思维,用 1 – 已停止序列的概率之和,从而得到 p(i)。

记 d[k] 表示 k 已经出现了 d[k] 次。已停止序列即所有的 1 <= k <= n 都满足 d[k] >= B[k]。

记 q[i] 表示已停止序列对应的概率,则有:

\[q[i] = \sum_{d[j] \ge B[j]}^{(\sum_{i=1}^{n}d[j])=i}\frac{i!}{\prod_{j=1}^{n}(d[j]!)}*\prod_{j=1}^{n}(\frac{A[j]}{SA})^{d[j]}
\]

注意到这个式子里面含有卷积,而且还以阶乘为分母。我们考虑将其改写成指数型生成函数的形式。

记 Q(x) 为 q 的指数型生成函数,则有:

\[Q(x) = \prod_{i=1}^{n}(\sum_{j=B[i]}\frac{(\frac{A[j]}{SA}x)^j}{j!})\\
=\prod_{i=1}^{n}(e^{\frac{A[j]}{SA}x}-\sum_{j=0}^{B[i]-1}\frac{(\frac{A[j]}{SA}x)^j}{j!})\]

设 P(x) 表示 p 的指数型生成函数,得到:

\[P(x) = e^x - Q(x)\\
=e^x - \prod_{i=1}^{n}(e^{\frac{A[j]}{SA}x}-\sum_{j=0}^{B[i]-1}\frac{(\frac{A[j]}{SA}x)^j}{j!})\]

这玩意儿可以暴力 O((∑B)^2*∑A) 展开。

展开后每一项长成 \(c_{i, j}e^{\frac{i}{SA}x}x^{j}\) 的形式,其中 i, j 满足 0 <= i <= ∑A, 0 <= j <= ∑B。

我们枚举 i, j,然后算 \(c_{i, j}e^{\frac{i}{SA}x}x^{j}\) 对答案的贡献。

记 t = i/SA。现暂且不考虑 \(c_{i, j}\),最后再乘。将 \(e^{tx}x^{j}\) 展开得到:

\[e^{tx}x^j=\sum_{i=0}\frac{t^ix^{i+j}}{i!}
\]

因为 \(x^{i+j}\) 对应的系数为 p[i+j]/(i+j)!,所以反过来求 p[i+j] 时需要乘 (i+j)!。因此贡献为:

\[S(j) = \sum_{i=0}t^i(i+j)^{\underline{j}}
\]

怎么求 S(j) 呢?利用下降幂的性质 \((i+1)^{\underline{j}} - i^{\underline{j}} = j*i^{\underline{j-1}}\),以及推导等比数列求和的过程,得到:

\[S(j) = \sum_{i=0}t^i(i+j)^{\underline{j}}\\
t*S(j) = \sum_{i=1}t^i(i+j-1)^{\underline{j}}\\
(1-t)*S(j) = j! + j*\sum_{i=1}t^i(i+j-1)^{\underline{j-1}} = j*S(j-1)
\]

因此得到 \(S(j) = \frac{j}{1-t}S(j-1)\)。

又因 j = 0 时就是等比数列求和,即 \(S(0) = \frac{1}{1-t}\),所以 \(S(j) = (\frac{1}{1-t})^{j+1}*j!\)。

总时间复杂度 O((∑B)^2*∑A)。

@accepted code - 1@

#include<cstdio>
const int MAXN = 400;
const int MOD = 998244353;
int inv[MAXN + 5];
struct mint{
int x;
mint(int _x=0) : x(_x) {}
friend mint operator + (const mint &a, const mint &b) {return a.x + b.x >= MOD ? a.x + b.x - MOD : a.x + b.x;}
friend mint operator - (const mint &a, const mint &b) {return a.x - b.x < 0 ? a.x - b.x + MOD : a.x - b.x;}
friend mint operator * (const mint &a, const mint &b) {return 1LL * a.x * b.x % MOD;}
friend mint operator / (const mint &a, const int &b) {return a * inv[b];}
};
mint pow_mod(mint b, int p) {
mint ret = 1;
while( p ) {
if( p & 1 ) ret = ret*b;
b = b*b;
p >>= 1;
}
return ret;
}
void init() {
inv[1] = 1;
for(int i=2;i<=MAXN;i++)
inv[i] = MOD - 1LL*inv[MOD%i]*(MOD/i)%MOD;
}
mint coef[MAXN + 5][MAXN + 5];
int A[MAXN + 5], B[MAXN + 5], N, SA, SB;
void read() {
scanf("%d", &N);
for(int i=0;i<N;i++)
scanf("%d%d", &A[i], &B[i]), SA += A[i], SB += B[i];
}
mint tmp[MAXN + 5][MAXN + 5];
void get() {
coef[0][0] = 1;
for(int i=0;i<N;i++) {
for(int j=0;j<=SA;j++)
for(int k=0;k<=SB;k++)
tmp[j][k] = coef[j][k], coef[j][k] = 0;
mint p = mint(A[i]) / SA, f = MOD - 1;
for(int l=0;l<B[i];l++,f=f/l*p)
for(int j=0;j<=SA;j++)
for(int k=l;k<=SB;k++)
coef[j][k] = coef[j][k] + f*tmp[j][k-l];
for(int j=A[i];j<=SA;j++)
for(int k=0;k<=SB;k++)
coef[j][k] = coef[j][k] + tmp[j-A[i]][k];
}
for(int i=0;i<=SA;i++)
for(int j=0;j<=SB;j++)
coef[i][j] = 0 - coef[i][j];
coef[SA][0] = coef[SA][0] + 1;
}
/*
let t = e^(x/S)
t^S - (t^Ai - (x*Ai/S)^j/j!)
*/
int solve() {
mint ret = 0, f = 1;
for(int j=0;j<=SB;j++,f=f*j)
for(int i=0;i<=SA;i++) {
mint p = mint(i) / SA;
p = pow_mod(1 - p, MOD - 2 - j);
ret = ret + coef[i][j]*p*f;
}
return ret.x;
}
int main() {
init(), read(), get();
printf("%d\n", solve());
}

@solution - 2@

这道题会很容易令人想起 uoj - 449 那道题。

我们尝试使用 min-max 容斥能否解决。

对于某一集合 S = {x1, x2, ..., xm},我们想要求它最早达到 Bi 的限制的期望时刻。

还是转化一下问题,求第 t 时刻没有任何元素达到 Bi 的概率 p(t),将 p(t) 求和即是期望。

因此,这个集合的贡献如下所示:

\[(-1)^{m+1}*\frac{SA}{\sum A[xi]}*\sum_{0\le di < B[xi]}\frac{(\sum di)!}{\prod(di!)}*\prod(\frac{A[xi]}{\sum A[xi]})^{di}
\]

前面的 \((-1)^{m+1}\) 为容斥系数,\(\frac{SA}{\sum A[xi]}\) 为在集合内抽中一个数的期望。

显然我们不能枚举每个集合然后算。考虑往集合内加入一个元素 y,贡献会怎么变:

\[(-1)^{m+2}*\frac{SA}{A[y] + \sum A[xi]}*\sum_{0\le di < B[xi]}\sum_{0\le dy < B[y]}\frac{(dy + \sum di)!}{dy!*\prod(di!)}*\prod(\frac{A[xi]}{A[y] + \sum A[xi]})^{di}*(\frac{A[y]}{A[y] + \sum A[xi]})^{dy}
\]

通过观察式子,假如我们限制以前的集合中 \(\sum A[xi] = p\),\(\sum di = q\);并在加入 y 的时候枚举 dy,则贡献是不受其他条件影响的。

记 f[i][p][q] 表示已经考虑了 n 个数中的前 i 个数,当前集合 \(\sum A[xi] = p, \sum di = q\),所有与 p, q 无关的值的乘积之和。

与 p, q 无关的值实际上就是 \((-1)*\frac{A[xi]^{di}}{di!}\),转移时乘一下这个即可。

最后再把 f[n][p][q] 拿出来算贡献即可。

总共转移不超过 O(∑Bi) 次,时间复杂度为 O((∑Bi)^2*Ai)。

@accepted code - 2@

#include<cstdio>
const int MOD = 998244353;
const int MAXN = 400;
int inv[MAXN + 5];
void init() {
inv[1] = 1;
for(int i=2;i<=MAXN;i++)
inv[i] = MOD - 1LL*inv[MOD%i]*(MOD/i)%MOD;
}
struct modint{
int x;
modint(int _x=0):x(_x) {}
friend modint operator + (modint x, modint y) {return (x.x + y.x) >= MOD ? x.x + y.x - MOD : x.x + y.x;}
friend modint operator - (modint x, modint y) {return (x.x - y.x) < 0 ? x.x - y.x + MOD : x.x - y.x;}
friend modint operator * (modint x, modint y) {return 1LL*x.x*y.x%MOD;}
friend modint operator / (modint x, int k) {return x*inv[k];}
};
modint pow_mod(modint b, int p) {
modint ret = 1;
while( p ) {
if( p & 1 ) ret = ret*b;
b = b*b;
p >>= 1;
}
return ret;
}
modint f[2][MAXN + 5][MAXN + 5];
int A[MAXN + 5], B[MAXN + 5], SA, SB;
int main() {
init();
int n; scanf("%d", &n);
for(int i=0;i<n;i++)
scanf("%d%d", &A[i], &B[i]), SA += A[i], SB += B[i];
f[0][0][0] = MOD - 1;
for(int i=0;i<n;i++) {
for(int j=0;j<=SA;j++)
for(int k=0;k<=SB;k++)
f[1][j][k] = f[0][j][k];
modint p = 1;
for(int l=0;l<B[i];l++,p=p*A[i]/l)
for(int j=A[i];j<=SA;j++)
for(int k=l;k<=SB;k++)
f[0][j][k] = f[0][j][k] - f[1][j-A[i]][k-l]*p;
}
modint ans = 0;
for(int j=1;j<=SA;j++) {
modint p = 1, q = modint(SA)/j;
for(int k=0;k<=SB;k++,p=p*k/j)
ans = ans + f[0][j][k]*p*q;
}
printf("%d\n", ans.x);
}

@details@

主要是式子的推导,其实代码实现本身没有太大难度。

这个题涉及了好多组合数学以及期望概率的套路。

@atcoder - AGC038E@ Gachapon的更多相关文章

  1. Atcoder Grand Contest 038 E - Gachapon(Min-Max 容斥+背包)

    Atcoder 题面传送门 & 洛谷题面传送门 我竟然能独立做出 Ag 的 AGC E,incredible!更新了 Atcoder 做题难度上限( 首先按照套路 Min-Max 容斥,\(a ...

  2. AtCoder Grand Contest 038E - Gachapon

    \(\bf Description\) 一个 \(0\) 到 \(n-1\) 的随机数生成器,生成 \(i\) 的概率是 \(A_i/S\) ,其中 \(S=\sum_{i=0}^{n} A_i\) ...

  3. AtCoder Regular Contest 061

    AtCoder Regular Contest 061 C.Many Formulas 题意 给长度不超过\(10\)且由\(0\)到\(9\)数字组成的串S. 可以在两数字间放\(+\)号. 求所有 ...

  4. AtCoder Grand Contest 001 C Shorten Diameter 树的直径知识

    链接:http://agc001.contest.atcoder.jp/tasks/agc001_c 题解(官方): We use the following well-known fact abou ...

  5. AtCoder Regular Contest 082

    我都出了F了……结果并没有出E……atcoder让我差4分上橙是啥意思啊…… C - Together 题意:把每个数加1或减1或不变求最大众数. #include<cstdio> #in ...

  6. AtCoder Regular Contest 069 D

    D - Menagerie Time limit : 2sec / Memory limit : 256MB Score : 500 points Problem Statement Snuke, w ...

  7. AtCoder Regular Contest 076

    在湖蓝跟衡水大佬们打的第二场atcoder,不知不觉一星期都过去了. 任意门 C - Reconciled? 题意:n只猫,m只狗排队,猫与猫之间,狗与狗之间是不同的,同种动物不能相邻排,问有多少种方 ...

  8. AtCoder Grand Contest 016

    在雅礼和衡水的dalao们打了一场atcoder 然而窝好菜啊…… A - Shrinking 题意:定义一次操作为将长度为n的字符串变成长度n-1的字符串,且变化后第i个字母为变化前第i 或 i+1 ...

  9. AtCoder Beginner Contest 069【A,水,B,水,C,数学,D,暴力】

    A - K-City Time limit : 2sec / Memory limit : 256MB Score : 100 points Problem Statement In K-city, ...

随机推荐

  1. Hackerrank--XOR love (Math系列)

    题目链接 Devendra loves the XOR operation very much which is denoted by ∧ sign in most of the programmin ...

  2. codeforces 545E E. Paths and Trees(单源最短路+总权重最小)

    E. Paths and Trees time limit per test:3 seconds memory limit per test:256 megabytes input:standard ...

  3. 百度the big talk节目

    主要事件 2015-03-09期:硅谷峰会:智能机器人&对话沃兹尼亚克 2015-03-02期:硅谷峰会:创新金融和智能城市 2015-02-15期:硅谷峰会:数字生物学和数字医药 2015- ...

  4. 【springmvc学习】常用注解总结

    @Controller 在springmvc中,我们用它来告诉前端控制器,他这个类是controller,也就是springmvc的一个对象了,我们在spring.xml配置文件中用<conte ...

  5. tesseract训练手写体

    前面的步骤都一样,从第4步开始 4.使用tesseract生成.box文件: tesseract eng.handwriting.exp0.tif eng.handwriting.exp0 -l en ...

  6. 代码规范:在Keil5中使用代码格式化工具Astyle(插件)

    r如果日志提示没有被格式化,那么检查你的文件是不是有错误,编译一下,没错误的时候才能格式化 keil mdk都啥年代了每次更新还是都无法解决补全bug也不添加格式化工具 所以这里要用一个第三方插件ht ...

  7. GIT → 02:Git和Svn比较

    2.1 SVN介绍 2.1.1 SVN简介 SVN 属于集中式版本管理控制系统,服务器中保存了所有文件的不同版本,而协同工作人员通过连接svn服务器,提取出最新的文件,获取提交更新.Subversio ...

  8. Linux预习

    目录 linux系统和unix系统的简介 linux系统和unix系统的简介 unix是什么:和widows一样 特点:多用户,多任务 同一时刻,多用户同时执行多项程序,互不干扰 GNU项目 就是一个 ...

  9. python 线性代数模块linalg

  10. 【模板】tarjanLCA [2017年6月计划 学习tarjanLCA]

    P3379 [模板]最近公共祖先(LCA) 题目描述 如题,给定一棵有根多叉树,请求出指定两个点直接最近的公共祖先. 输入输出格式 输入格式: 第一行包含三个正整数N.M.S,分别表示树的结点个数.询 ...