• @atcoder



    @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
    ", 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_{0le 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_{0le di < B[xi]}sum_{0le 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
    ", ans.x);
    }
    

    @details@

    主要是式子的推导,其实代码实现本身没有太大难度。
    这个题涉及了好多组合数学以及期望概率的套路。

  • 相关阅读:
    ContactManager示例解析
    CubeLiveWallpaper例子解析
    BluetoothChat例子解析
    推荐一个模板引擎 templateengine
    jQuery plugin: Autocomplete
    乐从网站建设、域名、主机-www.lecong.me-www.lecong.mobi
    C#操作注册表
    .NET模板引擎
    [转]模版引擎AderTemplate源代码分析笔记
    windows服务器文件同步,网站同步镜像
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/11736325.html
Copyright © 2020-2023  润新知