【题解】P5326 [ZJOI2019] 开关

P5326 [ZJOI2019] 开关

题意

有一个 \(n\) 个二进制位的二进制数,初始时每一位都为 \(0\)

每个单位时间,会随机取反一个二进制位。

对于第 \(i\) 位,它被取反的概率为 \(\displaystyle \frac{a_i}{\sum_{i=1}^n a_i}\)

求出达到状态 \(S\) 的期望时间。

\(\displaystyle n\le 100\)\(\displaystyle \sum_{i=1}^n a_i \le 5\times 10^4\)

题解

神题啊。

\(\displaystyle \sum_{i=1}^n a_i=m\)

\(p_i=\displaystyle \frac{a_i}{m}\),得到概率。

\(f_S\) 为达到状态 \(S\) 的期望时间,初始有 \(f_0=0\)

有转移,

\[\displaystyle f_S=1+\sum_{i=1}^{n} f_{S\oplus \{i\}}\times p_i \]

\(\oplus\) 表示异或操作,那么 \(S\oplus i\) 就表示将 \(S\) 的第 \(i\) 位取反,从集合的方面讲,就是切换 \(i\)\(S\) 中的存在性。

容易发现这个转移具有后效性,但是没关系,这相当于解一个有 \(2^n\) 个未知数的线性方程组,直接上高斯消元可以做到 \(O((2^n)^3)=O(8^n)\) 的时间复杂度,可以获得 \(40\) 分。

但这还远远不够,注意到上式可以转化成一个异或卷积的形式,

\[\displaystyle f_S=1+\sum_{i=1}^n f_{S\oplus \{i\}}\times p_i=1+\sum_{A\oplus B=S}f_A\times g_B \]

其中对于 \(g_B\) 的定义如下:

\[g_B= \begin{cases} p_i&&|B|=1,i\in B\\ 0&&\text{otherwise} \end{cases}\]

那多半和集合幂级数脱不了什么干系了。

记全集 \(U=\{1,2,\dots,n\}\)\(2^U\) 表示 \(U\) 的幂集,即 \(U\) 的所有子集组成的集合,无特殊说明,下文提到的所有集合都是 \(2^U\) 的子集,故省略 \(\in 2^U\)

\(\displaystyle f=\sum_{S}f_S x^S\)\(\displaystyle g=\sum_{\{i\}} p_i x^{\{i\}}\)\(\displaystyle I=\sum_{S}x^S\)

\(f_S\) 表示 \(f\)\(x^S\) 前面的系数,而 \(f\cdot g\) 表示 \(f\)\(g\) 的异或卷积,\(\widehat f\) 表示异或 FWT 之后的 \(f\)

根据异或 FWT 的定义,有,

\[\displaystyle \widehat f_S=\sum_{T} (-1)^{|S\cap T|} f_T \]

同样对于逆变换 IFWT 有,

\[\displaystyle f_S=\frac{1}{2^n} \sum_{T} (-1)^{|S\cap T|} \widehat f_T \]

尝试把之前的转移式写成集合幂级数的形式,

\[f=I+f\cdot g \]

感觉没什么问题,但是上式忽略了一个事实,\(f_{\empty}=0\),所以后面还要加上一个 \(rx^{\empty}\),使得最终 \(f_{\empty}=0\),也就是,

\[f=I+f\cdot g+rx^{\empty} \]

尝试将两边都做一遍 FWT,

\[\widehat f=\widehat I+\widehat f \times \widehat g + \widehat{rx^{\empty}} \]

对于每个 \(S\) 都有,

\[\widehat f_S=\widehat I_S+\widehat f_S \times \widehat g_S + r \]

注意到在变换后 \(f\cdot g\) 变为了 \(\widehat f \times \widehat g\),这里强调的是其变为了点乘的形式。

那么移项得到,

\[\widehat f_S(1-\widehat g_S)=\widehat I_S + r \]

\(S=\empty\) 时,为了保证 \(f_{\empty}=0\),上式应仍然保持成立。

此时 \(\displaystyle \widehat g_{\empty}=\sum_{T} (-1)^{|\empty\cap T|} g_T=\sum_{T}g_T=\sum_{i=1}^n p_i=1\),所以等式左边为 \(0\)

同理可以计算出 \(\widehat I_{\empty}=2^n\),所以 \(r=-2^n\)

\(S\neq \empty\) 时,可以发现一定有 \(\widehat I_S=0\),证明如下,

参照定义有,

\[\displaystyle \widehat I_S=\sum_{T} (-1)^{|S\cap T|} I_T \]

\[\displaystyle \widehat I_S=\sum_{T} (-1)^{|S\cap T|} \]

等价于,

\[\displaystyle \widehat I_S=\sum_{(x_1,\dots,x_n)\in\{0,1\}^n} (-1)^{\sum_{i=1}^n [i\in S]x_i} \]

\[\displaystyle \widehat I_S=\sum_{(x_1,\dots,x_n)\in\{0,1\}^n} \prod_{i=1}^n(-1)^{[i\in S]x_i} \]

\[\displaystyle I_S=\sum_{x_1=0}^1\dots\sum_{x_n=0}^1 \prod_{i=1}^n(-1)^{[i\in S]x_i} \]

\[\displaystyle I_S=\sum_{x_1=0}^1 (-1)^{[1\in S]x_1}\dots\sum_{x_n=0}^1 (-1)^{[n\in S]x_n} \]

即,

\[\displaystyle I_S=\prod_{i=1}^n (\sum_{x_i=0}^1(-1)^{[i\in S]x_i}) \]

\[\displaystyle I_S=\prod_{i=1}^n (1+(-1)^{[i\in S]}) \]

也就是,

\[\displaystyle I_S=\prod_{i\in S}0\times \prod_{i\not \in S} 2 \]

\[\widehat I_S=\begin{cases} 2^n&&S=\empty\\ 0&&S\neq \empty \end{cases} \]

至此得证。

假设 \(S\neq \empty\),则 \(\widehat f_S\) 可以表示为,

\[\widehat f_S=\frac{r}{1-\widehat g_S} \]

\[\widehat f_S=-\frac{2^n}{1-\widehat g_S} \]

发现 \(\widehat g_S\) 还没怎么发掘过,依旧是根据定义得到,

\[\displaystyle \widehat g_S=\sum_{T} (-1)^{|S\cap T|} g_T \]

根据前文定义,若 \(|S|\neq 1\)\(g_S=0\),所以有意义的只有 \(|S|=1\) 时的 \(g_S\),考虑换一种表示方式,

\[\displaystyle \widehat g_S=\sum_{\{i\}} (-1)^{|S\cap \{i\}|} p_i \]

即为,

\[\displaystyle \widehat g_S=-\sum_{i\in S}p_i+\sum_{i\not \in S}p_i \]

取补集,

\[\displaystyle \widehat g_S=1-2\sum_{i\in S}p_i \]

代入上面推了一半的式子,

\[\widehat f_S=-\frac{2^n}{\displaystyle 2\sum_{i\in S}p_i} \]

此时用一次逆变换的定义式,

\[\displaystyle f_S=\frac{1}{2^n} \sum_{T} (-1)^{|S\cap T|} \widehat f_T \]

发现 \(T=\empty\)\(\widehat f_T\) 不太好处理,考虑利用 \(f_\empty=0\) 的性质,

\[\displaystyle 0=\widehat f_{\empty}+\sum_{T\neq \empty} (-1)^{|\empty\cap T|} \widehat f_T \]

移项化简得到,

\[\displaystyle \widehat f_{\empty}=-\sum_{T\neq \empty}\widehat f_T \]

把它再代回定义式,

\[\displaystyle f_S=\frac{1}{2^n}(-\sum_{T\neq \empty}\widehat f_T + \sum_{T\neq \empty} (-1)^{|S\cap T|} \widehat f_T ) \]

\[\displaystyle f_S=\frac{1}{2^n}\sum_{T\neq \empty} ((-1)^{|S\cap T|}-1)\times \widehat f_T \]

观察到 \((-1)^{|S\cap T|}-1\in \{0,-2\}\),考虑改变形式,

\[\displaystyle f_S=-\frac{2}{2^n}\sum_{T\neq \empty} (|S\cap T|\bmod 2) \times \widehat f_T \]

此时果断代入前面推出来的 \(\widehat f_T\) 关于 \(p_i\) 的式子,

\[\displaystyle f_S=-\frac{2}{2^n}\sum_{T\neq \empty}(|S\cap T|\bmod 2)(-\frac{2^n}{\displaystyle 2\sum_{i\in T}p_i}) \]

直接化简,

\[\displaystyle f_S=\sum_{T\neq \empty}(|S\cap T|\bmod 2) \frac{1}{\displaystyle \sum_{i\in T}p_i} \]

换成 \(a_i\)

\[\displaystyle f_S=m\sum_{T\neq \empty}(|S\cap T|\bmod 2) \frac{1}{\displaystyle \sum_{i\in T}a_i} \]

\(\displaystyle n\le 100\)\(\displaystyle \sum_{i=1}^n a_i \le 5\times 10^4\),式子中 \(S\) 就是题目给定的 \(S\),这显然可以让做一个背包 dp 计数。

具体地,设 \(dp_{i,j,k}\) 表示考虑了前 \(i\) 位,选定的 \(a_i\) 总和为 \(j\)\(|S\cap T|\bmod 2=k\),此时的方案数,根据目标状态 \(S\) 这一位是 \(0\) 还是 \(1\) 来分类去转移就行了。

那么答案就是 \(\displaystyle m\sum_{i=1}^m \frac{f_{n,i,1}}{i}\)

时间复杂度 \(O(nm+m\log P)\)\(P\) 是模数。

#include<bits/stdc++.h>
using namespace std;

#define rep(i,l,r) for(int i=(l);i<=(r);++i)
#define per(i,l,r) for(int i=(r);i>=(l);--i)
#define pr pair<int,int>
#define fi first
#define se second
#define pb push_back
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define bg(x) (x).begin()
#define ed(x) (x).end()

#define N 105
#define M 50010
#define int long long

const int mod=998244353;
int n,s[N],p[N],m,dp[M][2];

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

inline int qpow(int a,int b=mod-2){
    int ans=1;

    while(b){
        if(b&1){
            ans=ans*a%mod;
        }
        a=a*a%mod;
        b>>=1;
    }

    return ans;
}

signed main(){
    // freopen(".in","r",stdin);
    // freopen(".out","w",stdout);
    ios::sync_with_stdio(0);
    cin.tie(0);cout.tie(0);

    cin>>n;

    rep(i,1,n){
        cin>>s[i];
    }

    rep(i,1,n){
        cin>>p[i];
        m+=p[i];
    }

    dp[0][0]=1;

    rep(i,1,n){
        per(j,p[i],m){
            if(!s[i]){
                add(dp[j][0],dp[j-p[i]][0]);
                add(dp[j][1],dp[j-p[i]][1]);
            }
            else{
                add(dp[j][1],dp[j-p[i]][0]);
                add(dp[j][0],dp[j-p[i]][1]);
            }
        }
    }

    int ans=0;

    rep(i,1,m){
        add(ans,dp[i][1]*qpow(i)%mod);
    }

    cout<<ans*m%mod;

    return 0;
}
posted @ 2025-08-22 00:30  Lucyna_Kushinada  阅读(23)  评论(0)    收藏  举报