「ZJOI2019」开关 (概率期望+FWT)

Address

Luogu#5326

LOJ#3045

Solution

首先把目标状态和初始状态互换,答案显然不变。

考虑状压 \(\text{dp}\),现在记 \(F[S]\) 表示初始状态为 \(S\) 时,期望多少步到达目标状态。

接下来假设 \(\sum_{i=1}^np_i=1\),如果输入不满足,把 \(p_i\) 全部除以 \(\sum p_i\) 即可。

那么有:$$F[\emptyset]=0$$ $$S\ne\emptyset,F[S]=\sum_ip_i×(F[S\oplus \left{i\right}]+1)$$ 其中 \(\oplus\) 表示异或,\(\left\{i\right\}\) 表示只含 \(i\) 这一个元素的集合。

\(G[\left\{i\right\}]=p_i\),当 \(|S|\ne 1\) 时,\(G[S]=0\)

定义两个数组的异或卷积:如果 \(C=A\times B\),那么有:$$\forall S,C[S]=\sum_U\sum_V[U\oplus
V=S]A[U]×B[V]$$

定义两个数组的点积:如果 \(C=A\cdot B\),那么有 $$\forall S,C[S]=A[S]\times B[S]$$

定义两个数组相加:如果 \(C=A+B\),那么有 $$\forall S,C[S]=A[S]+B[S]$$

记一个全 \(1\) 数组 \(H\),即 \(\forall S,H[S]=1\)

定义数组 \(R\),其中 \(R[\emptyset]=c\)\(\forall S\ne\emptyset,R[S]=0\)\(c\) 的值暂时还不知道,先用字母表示。

那么可以得到:$$F=H+F×G+R$$ \(R\) 的存在是由于 \(S=\emptyset\)\(S\ne \emptyset\) 时,\(F[S]\) 的递推式不一样。

定义变换 \(\tilde C\)(这玩意就是 \(FWT\) 变换,已经会的自觉跳过),其中 $$\tilde
C[S]=\sum_T(-1)^{|S\cap T|}C[T]$$

根据上式显然有:如果 \(C=A+B\),那么 \(\tilde C=\tilde A+\tilde B\)

而且可以得到 $$C[S]=\frac{1}{2n}\sum_T(-1)\tilde C[T]$$

其中 \(n\)\(S\) 的二进制位数,考虑证明上式。

相当于证明:$$C[S]=\frac{1}{2n}\sum_A\sum_B(-1)(-1)^{|A\cap
B|}C[B]$$

\(S=B\) 时,上式化为 $$C[S]=\frac{1}{2n}\sum_A(-1)C[B]$$

即 $$C[S]=\frac{1}{2^n}\sum_AC[B]$$

显然成立。

\(S\ne B\) 时,我们随便抓一个只在 \(S,B\) 其中一者中出现的元素 \(i\)。对于某个集合 \(A'\),如果 \(i\notin A'\),那么 \(A=A'\)\(A=A'+\left\{i\right\}\) 的贡献互为相反数,因为:$$(-1)^{|S\cap
A'|}(-1)^{|A'\cap B|}=-(-1)^{|S\cap
(A'+\left{i\right})|}(-1)^{|(A'+\left{i\right})\cap B|}$$

而这样的 \(A'\) 正好有 \(2^{n-1}\) 个,也就是说所有的 \(A\) 可以两两配对,贡献全部抵消,那么 \(S\ne B\)
的时候就有:$$\frac{1}{2n}\sum_A(-1)(-1)^{|A\cap B|}=0$$

证毕。

有个性质:若 \(C=A\times B\),那么 \(\tilde C=\tilde A\cdot \tilde B\),证明如下:

\[C[S]=\sum_L\sum_R[L\oplus R\oplus S=0]A[L]B[R] \]

因为 \(\sum_T(-1)^{|S\cap T|}=2^n[S=\emptyset]\),所以:

\[C[S]=\frac{1}{2^n}\sum_L\sum_R\sum_T(-1)^{|T\cap(L\oplus R\oplus S)|}A[L]B[R]\]

接着,显然有 $$T\cap(L\oplus R\oplus S)=(T\cap L)\oplus(T\cap R)\oplus(T\cap
S)$$

那么 $$(-1)^{|T\cap(L\oplus R\oplus S)|}=(-1)^{|T\cap L|+|T\cap
R|+|T\cap S|}$$

上式可以理解为:若 \(z=x\oplus y\),那么 \(|z|\&1=(|x|+|y|)\&1\),因为异或相当于二进制下的不进位加法,所以
\(x\oplus y\) 时,\(x,y\) 二进制中的 \(1\) 只会两两一起消掉,\(1\) 的总数的奇偶性不会变。

所以

\[C[S]=\frac{1}{2^n}\sum_L\sum_R\sum_T(-1)^{|T\cap L|}(-1)^{|T\cap R|}(-1)^{|T\cap S|}A[L]B[R]\]

\[C[S]=(\frac{1}{2^n}\sum_T(-1)^{|T\cap S|})(\sum_L(-1)^{|T\cap L|}A[L])(\sum_R(-1)^{|T\cap R|}B[R])\]

\[C[S]=(\frac{1}{2^n}\sum_T(-1)^{|T\cap S|})\tilde A[T]\times\tilde B[T]\]

根据 $$C[S]=\frac{1}{2n}\sum_T(-1)\tilde C[T]$$

可得 $$\tilde C[T]=\tilde A[T]\times\tilde B[T]$$

证毕。

让我们回到:$$F=H+F×G+R$$

移项,得到 $$F(1-G)=H+R$$

\(A=F(1-G)\),则 $$\tilde A[U]=\tilde F[U]×(1-\tilde G[U])$$

\(A=H+R\),则 $$\tilde A[U]=\sum_T(-1)^{|T\cap U|}+c$$

于是 $$\tilde F[U]×(1-\tilde G[U])=\sum_T(-1)^{|T\cap U|}+c$$

\(U=\emptyset\) 时,有:$$\tilde G[U]=\sum p_i=1$$

代入上式可得 \(c=-2^n\)

\(U\ne\emptyset\) 时,有:$$\tilde G[U]=\sum_{i}(-1)^{[i∈U]}p_i$$

此时 \(\tilde G[U]<1\),代入上式可得:

\[\tilde F[U]=\frac{c}{1-\tilde G[U]}=-\frac{2^n}{1-\tilde G[U]} \]

根据式子 $$\sum_T(-1)^{|S\cap T|}=2^n[S=\emptyset]$$

可得 $$\sum_T\tilde F[T]=2^nF[\emptyset]=0$$

那么 $$\tilde F[\emptyset]=-\sum_{T\ne \emptyset}\tilde F[T]=\sum_{T\ne \emptyset}\frac{2^n}{1-\tilde G[T]}$$

现在可以由 \(\tilde F\) 变回 \(F\) 了,即 $$F[S]=\frac{1}{2n}\sum_T(-1)\tilde F[T]$$

根据上面 \(\tilde F\) 的表达式,可得 $$F[S]=\sum_{T}(1-(-1)^{|S\cap T|})\frac{1}{1-\tilde G[T]}$$

根据 \(\tilde G\) 的表达式可得 $$1-\tilde G[T]=\sum_{i∈T}2×p_i$$

那么 $$F[S]=\sum_{T}(|S\cap T|&1)\frac{1}{\sum_{i∈T}p_i}$$

\(dp[i][j][k]\) 表示前 \(i\) 个数的子集,和 \(S\) 交集大小的奇偶性为 \(k\),子集的 \(p\) 之和为 \(j\),满足这些条件的子集个数。

那么 $$ans=\sum_j\frac{dp[n][j][1]}{j}$$

但是如果 \(p_i\) 全部除以 \(\sum_{i=1}^np_i\)\(p_i\) 就不是整数了,无法 \(dp\)。所以一开始不要把 \(p_i\) 除以 \(\sum p_i\),直接 \(dp\)。 最后再把答案乘上 \(\sum p_i\) 即可。

时间复杂度 \(\mathcal O(n\sum p_i)\)

Code

#include <bits/stdc++.h>

using namespace std;

#define ll long long

template <class t>
inline void read(t & res)
{
	char ch;
	while (ch = getchar(), !isdigit(ch));
	res = ch ^ 48;
	while (ch = getchar(), isdigit(ch))
	res = res * 10 + (ch ^ 48);
}

const int e = 105, o = 5e4 + 5, mod = 998244353;

int n, s[e], p[e], sum, inv[o], f[e][o][2], ans;

inline void add(int &x, int y)
{
	(x += y) >= mod && (x -= mod);
}

int main()
{
	read(n);
	int i, j;
	for (i = 1; i <= n; i++) read(s[i]);
	for (i = 1; i <= n; i++) read(p[i]), sum += p[i];
	inv[1] = 1;
	for (i = 2; i <= sum; i++) inv[i] = (ll)(mod - mod / i) * inv[mod % i] % mod;
	f[0][0][0] = 1;
	for (i = 1; i <= n; i++)
	for (j = 0; j <= sum; j++)
	{
		f[i][j][0] = f[i - 1][j][0];
		f[i][j][1] = f[i - 1][j][1];
		if (j >= p[i])
		{
			add(f[i][j][0], f[i - 1][j - p[i]][s[i]]);
			add(f[i][j][1], f[i - 1][j - p[i]][s[i] ^ 1]);
		}
	}
	for (i = 1; i <= sum; i++) ans = (ans + (ll)inv[i] * f[n][i][1]) % mod;
	ans = (ll)ans * sum % mod; 
	cout << ans << endl;
	return 0;
}
posted @ 2020-01-27 13:07  花淇淋  阅读(197)  评论(0编辑  收藏  举报