Address
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[S]=\frac{1}{2^n}\sum_T(-1)^{|S\cap T|}\tilde C[T]\]
其中 \(n\) 是 \(S\) 的二进制位数,考虑证明上式。
相当于证明:\[C[S]=\frac{1}{2^n}\sum_A\sum_B(-1)^{|S\cap A|}(-1)^{|A\cap B|}C[B]\]
当 \(S=B\) 时,上式化为 \[C[S]=\frac{1}{2^n}\sum_A(-1)^{2|S\cap A|}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}{2^n}\sum_A(-1)^{|S\cap A|}(-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}{2^n}\sum_T(-1)^{|S\cap T|}\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}{2^n}\sum_T(-1)^{|S\cap T|}\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;
}