[ZJOI2019] 开关

Description

Link\rm Link

Solution

为了方便,做如下定义:
FF 为集合幂级数,则 FsF_s 表示 [xs]F[x^{s}]F


这道题和 RNG and XOR\text{RNG and XOR} 做法类似,感觉挺常考的,遂总结一下。

fsf_s 表示从初始状态开始,达到「只有集合 ss 中含有的开关打开,其余的开关关闭的」状态的期望步数。
psp_s 表示一次按开关的集合为 ss 的概率(显然只有元素个数为 11 的集合有值,其余均为 00)。
那么可以得到:

fs={0                          s=ab=sfapb+1      sf_s= \begin{cases} 0\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ s=\emptyset\\ \sum\limits_{a\oplus b=s} f_ap_b+1\ \ \ \ \ \ s\neq \emptyset \end{cases}

这是方程的形式。

FF 为一个「下标和指数为集合的多项式」,并且 F=s[n]fsxsF=\sum_{s\subseteqq [n]}f_sx^s。同理定义 P=s[n]psxsP=\sum_{s\subseteqq [n]}p_sx^s

这也就是 VFK\rm VFK 所说的「集合幂级数」。

定义该多项式的乘法为异或卷积,那么我们可以写出如下方程:

F=FP+IF=F*P+I

事实上这个方程有点问题。观察可以发现,左右两边在 xx^{\emptyset} 处的系数是不一样的,而且只有这个位置不同。
S(G)S(G) 表示多项式 GG 的系数和。则我们可以列出:

S(F)=S(F)×S(P)+S(I)S(F)=S(F)\times S(P)+S(I)

显然,S(P)=1,S(I)=2nS(P)=1,S(I)=2^n 。所以左边在 xx^{\emptyset} 处应该还有一个 2n2^n 的系数。于是可以写出最终方程:

2n+F=FP+I2^n+F=F*P+I

变形可得:

F=I2n(1P)F=\frac{I-2^n}{(1-P)}

F^\widehat{F} 表示多项式 FF FWT\rm FWT 后的多项式。则有:

F^s=I2n^s1P^s        (s=)\widehat{F}_s=\frac{\widehat{I-2^n}_s}{\widehat{1-P}_s}\ \ \ \ \ \ \ \ (s\not ={\emptyset})

这个式子不够简洁,我们进一步化简。FWT\rm FWT 前在 xx^{\emptyset} 处加常数 cc ,相当于在 FWT\rm FWT 后每一位加该常数 cc 据此可以转化上式得(I^s\widehat{I}_ss=s\not ={\emptyset} 时恒等于 00):

F^s=2n1P^s         (s=)\widehat{F}_s=\frac{-2^n}{1-\widehat{P}_s}\ \ \ \ \ \ \ \ \ (s\not ={\emptyset})

由该式易知当 s=s=\emptyset 时右边分母为 00 ,所以之前规定 s=s\not ={\emptyset}

AGC\rm AGC 那道题目到这里就结束了... 直接 FWT\rm FWTIFWT\rm IFWT 回去即可求出 FF

但是这道题到这里还没完。目前已经有 40pts\rm 40pts 了,可喜可贺。

事实上,我们最后相当于求出来了所有状态的期望。而题目只要求某一项的值。我们不应该笼统地 FWT\rm FWTIFWT\rm IFWT ,我们必须从 FWT\rm FWTIFWT\rm IFWT 的本质入手,直接求出最后要求的 FSF_S 。这就要求我们拆 FWT\rm FWTIFWT\rm IFWT 的式子。

FWT\rm FWT 变换的式子如下:

F^x=s[n](1)s and xFs\widehat{F}_x=\sum_{s\subseteqq [n]}(-1)^{|s\text{ and } x|}F_s

IFWT\rm IFWT 变换的式子如下:

Fx=12ns[n](1)s and xF^sF_x=\frac{1}{2^n}\sum_{s\subseteqq [n]}(-1)^{|s\text{ and } x|}\widehat{F}_s

最后相当于是要求 FSF_S 的值。那么我们用 IFWT\rm IFWT 展开它:

FS=12ns[n](1)S and sF^s=F^2ns[n],s=(1)S and s11P^s\begin{aligned} F_S&=\frac{1}{2^n}\sum_{s\subseteqq [n]}(-1)^{|S\text{ and } s|}\widehat{F}_s\\ &=\frac{\widehat{F}_{\emptyset}}{2^n}-\sum_{s\subseteqq[n],s\not ={\emptyset}}(-1)^{|S\text{ and }s|}\frac{1}{1-\widehat{P}_s} \end{aligned}

因为 F=0F_{\emptyset}=0,根据 IFWT\rm IFWT 变换的式子可得:

F^2n=s[n],s=F^s2n=s[n],s=11P^s\frac{\widehat{F}_{\emptyset}}{2^n}=-\frac{\sum\limits_{s\subseteqq [n],s\not ={\emptyset}}\widehat{F}_s}{2^n}=\sum_{s\subseteqq [n],s\not ={\emptyset}}\frac{1}{1-\widehat{P}_s}

再带回去可以得到:

FS=2s[n][s and S1(mod2)]11P^sF_S=2\sum_{s\subseteqq [n]}[|s\text{ and } S|\equiv 1\pmod{2}]\frac{1}{1-\widehat{P}_s}

1P^s1-\widehat{P}_s 可以用之前 FWT\rm FWT 变换的式子转化。考虑到 PiP_i 中事实上只有 nn 个集合有值,那么我们完全可以把枚举集合转化为枚举元素,然后再化简式子:

1P^s=i=1n(Pi(1)[is]Pi)=is2Pi\begin{aligned} 1-\widehat{P}_s=\sum_{i=1}^{n}(P_i-(-1)^{[i\in s]}P_i)=\sum_{i\in s}2P_i \end{aligned}

所以可以得到最后的式子为

FS=s[n][s and S1(mod2)]1isPiF_S=\sum_{s\subseteqq [n]}[|s\text{ and } S|\equiv 1\pmod{2}]\frac{1}{\sum_{i\in s}P_i}

最后这个式子组合意义就十分明显了,直接 DP\rm DP 即可。
不会有人看到这里了看不出来这个 DP\sout{\text{DP}} 吧 不会吧不会吧

复杂度 O(np)\mathcal{O}(n\sum p)

Code

const int N = 1e2 + 5, M = 5e4 + 23, mod = 998244353;
using namespace std;
int n, sum;
int s[N], v[N];
int f[2][2][M];
inline void Plus(int &a, int b){
    a += b - mod, a += (a >> 31) & mod;
}
int qpow(long long b, int t){
    long long ret = 1;
    for(; t; t >>= 1, b = b * b % mod)
        if(t & 1) ret = ret * b % mod;
    return ret;
}
int main(){

    fin >> n;
    for(int i = 1; i <= n; ++i) 
        fin >> s[i];
    for(int i = 1; i <= n; ++i)
        fin >> v[i], sum += v[i];
    
    f[0][0][0] = 1;
    for(int i = 0; i < n; ++i){
        int p = i & 1, q = p ^ 1;
        memset(f[q], 0, sizeof f[q]);
        for(int j = 0; j <= 1; ++j)
        for(int k = 0; k <= sum; ++k) if(f[p][j][k]) {
            Plus(f[q][j][k], f[p][j][k]);
            Plus(f[q][j ^ s[i + 1]][k + v[i + 1]], f[p][j][k]);
        }
    }

    int ans = 0;
    for(int i = 1; i <= sum; ++i)
        Plus(ans, 1ll * qpow(i, mod - 2) * f[n & 1][1][i] % mod);
    
    cout << 1ll * ans * sum % mod << endl;
    return 0;
}