【LOJ3045】「ZJOI2019」开关

【题目链接】

【思路要点】

  • 无视结束条件,令 i i i 步之后状态全零的概率的指数型生成函数为 F ( x ) F(x) F(x) ,对应的普通型生成函数为 f ( x ) f(x) f(x) ,记 S = ∑ p i S=\sum p_i S=pi ,则有 F ( x ) = ∏ i = 1 N e x p ( p i S x ) + ( − 1 ) s i e x p ( − p i S x ) 2 F(x)=\prod_{i=1}^{N}\frac{exp(\frac{p_i}{S}x)+(-1)^{s_i}exp(-\frac{p_i}{S}x)}{2} F(x)=i=1N2exp(Spix)+(1)siexp(Spix)
  • 考虑去掉不是首次达到状态全零的概率,记 i i i 步之后状态不变的概率的指数型生成函数为 G ( x ) G(x) G(x) ,首次达到状态全零的概率的指数型生成函数为 H ( x ) H(x) H(x) ,对应的普通型生成函数分别为 g ( x ) , h ( x ) g(x),h(x) g(x),h(x) 。显然,有 G ( x ) = ∏ i = 1 N e x p ( p i S x ) + e x p ( − p i S x ) 2 G(x)=\prod_{i=1}^{N}\frac{exp(\frac{p_i}{S}x)+exp(-\frac{p_i}{S}x)}{2} G(x)=i=1N2exp(Spix)+exp(Spix)
    并且 h ( x ) g ( x ) = f ( x ) , h ( x ) = f ( x ) g ( x ) h(x)g(x)=f(x),h(x)=\frac{f(x)}{g(x)} h(x)g(x)=f(x),h(x)=g(x)f(x)
  • 需要计算的期望即为 h ′ ( 1 ) h'(1) h(1) 的值,即考虑计算 f ′ ( 1 ) g ( 1 ) − f ( 1 ) g ′ ( 1 ) g 2 ( 1 ) \frac{f'(1)g(1)-f(1)g'(1)}{g^2(1)} g2(1)f(1)g(1)f(1)g(1)
  • F ( x ) , G ( x ) F(x),G(x) F(x),G(x) 可以用定义式直接写作 ∑ i = − S S a i e x p ( i S x ) \sum_{i=-S}^{S}a_iexp(\frac{i}{S}x) i=SSaiexp(Six) ,考虑 e x p exp exp 的组合意义,将指数型生成函数转换为普通型生成函数,得到的结果应为 ∑ i = − S S a i 1 − i S x \sum_{i=-S}^{S}\frac{a_i}{1-\frac{i}{S}x} i=SS1Sixai
  • 直接将 x = 1 x=1 x=1 代入 f ( x ) , g ( x ) f(x),g(x) f(x),g(x) 求得的值趋于无穷,但注意到 h ( x ) = f ( x ) g ( x ) h(x)=\frac{f(x)}{g(x)} h(x)=g(x)f(x) ,不妨令 f ( x ) , g ( x ) f(x),g(x) f(x),g(x) 都乘上 ∏ i = − S S ( 1 + i S x ) \prod_{i=-S}^{S}(1+\frac{i}{S}x) i=SS(1+Six) ,这样 f ( x ) , g ( x ) , f ′ ( x ) , g ′ ( x ) f(x),g(x),f'(x),g'(x) f(x),g(x),f(x),g(x) 显然在 x = 1 x=1 x=1 处就都有实数取值了。
  • 记新得到的 f ( x ) = ∑ i = − S S a i ∏ j = − S , j ≠ i S ( 1 + j S x ) = a − S ∏ j = − S + 1 S ( 1 + j S x ) f(x)=\sum_{i=-S}^{S}a_i\prod_{j=-S,j\ne i}^{S}(1+\frac{j}{S}x)=a_{-S}\prod_{j=-S+1}^{S}(1+\frac{j}{S}x) f(x)=i=SSaij=S,j̸=iS(1+Sjx)=aSj=S+1S(1+Sjx)
  • f ( x ) f(x) f(x) 求导,得 f ′ ( x ) = ∑ i = − S S a i ∑ j = − S , j ≠ i S j S ∏ k = − S , k ≠ i , j S ( 1 + k S x ) f'(x)=\sum_{i=-S}^{S}a_i\sum_{j=-S,j\ne i}^{S}\frac{j}{S}\prod_{k=-S,k\ne i,j}^{S}(1+\frac{k}{S}x) f(x)=i=SSaij=S,j̸=iSSjk=S,k̸=i,jS(1+Skx)
  • 计算上式时只需计算 i = − S i=-S i=S j = − S j=-S j=S 的情况即可,其余情况 ∏ \prod 内的值为 0 0 0
  • 时间复杂度 O ( N V + V L o g V ) O(NV+VLogV) O(NV+VLogV)

【代码】

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 105;
const int MAXV = 1e5 + 5;
const int P = 998244353;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
template <typename T> void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
	write(x);
	puts("");
}
int n, sum, invs, s[MAXN], p[MAXN];
int f[MAXV], g[MAXV];
void update(int &x, int y) {
	x += y;
	if (x >= P) x -= P;
}
int power(int x, int y) {
	if (y == 0) return 1;
	int tmp = power(x, y / 2);
	if (y % 2 == 0) return 1ll * tmp * tmp % P;
	else return 1ll * tmp * tmp % P * x % P;
}
int func(int *f) {
	int ans = 1;
	for (int i = -sum + 1; i <= sum; i++)
		ans = 1ll * ans * (1 + (P + i + 0ll) * invs % P) % P;
	return 1ll * ans * f[0] % P;
}
int der(int *f) {
	static int tmp[MAXV];
	int ans = 0, tsum = 1;
	for (int i = -sum + 1; i <= sum; i++)
		tsum = 1ll * tsum * (1 + (P + i + 0ll) * invs % P) % P;
	for (int i = -sum + 1; i <= sum; i++)
		tmp[i + sum] = 1ll * tsum * power(1 + (P + i + 0ll) * invs % P, P - 2) % P;
	for (int i = -sum + 1; i <= sum; i++) {
		update(ans, 1ll * f[0] * (P + i) % P * invs % P * tmp[i + sum] % P);
		update(ans, 1ll * f[i + sum] * (P - sum) % P * invs % P * tmp[i + sum] % P);
	}
	return ans;
}
int main() {
	read(n);
	for (int i = 1; i <= n; i++)
		read(s[i]);
	for (int i = 1; i <= n; i++)
		read(p[i]), sum += p[i];
	int cur = 0; invs = power(sum, P - 2);
	f[sum] = g[sum] = 1;
	for (int i = 1; i <= n; i++) {
		static int tf[MAXV], tg[MAXV];
		memset(tf, 0, sizeof(tf));
		memset(tg, 0, sizeof(tg));
		for (int j = -cur; j <= cur; j++) {
			if (s[i] == 0) update(tf[j + sum - p[i]], f[j + sum]);
			else update(tf[j + sum - p[i]], P - f[j + sum]);
			update(tf[j + sum + p[i]], f[j + sum]);
			update(tg[j + sum - p[i]], g[j + sum]);
			update(tg[j + sum + p[i]], g[j + sum]);
		}
		cur += p[i];
		memcpy(f, tf, sizeof(tf));
		memcpy(g, tg, sizeof(tg));
	}
	reverse(f, f + 2 * sum + 1);
	reverse(g, g + 2 * sum + 1);
	int num = 0, den = 0;
	update(num, 1ll * func(g) * der(f) % P);
	update(num, P - 1ll * func(f) * der(g) % P);
	update(den, 1ll * func(g) * func(g) % P);
	writeln(1ll * num * power(den, P - 2) % P); 
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值