「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[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;
}

猜你喜欢

转载自www.cnblogs.com/cyf32768/p/12235774.html