【大联盟】20230516 T2 暑假最后一天(expert) 题解 P5326 【[ZJOI2019]开关】
大家可以猜猜看为什么有两个标题,因为这个原因本文就不设密码了。
题目描述
link。
题解
这里记录下异或卷积的做法,我们记 \(f_s\) 表示到 \(s\) 的期望步数,那么:
\[f_s=
\begin{cases}
f_s=0 &s=\varnothing\\
f_s=1+\sum\limits_{s'=s\oplus {j}} f_{s'}p_j &s\ne\varnothing
\end{cases}
\]
我们令:
\[g_s=
\begin{cases}
-1 & s = \varnothing\\
p_i & s = \{i\}\\
0 & |s| > 1
\end{cases}
\]
\[h_s=
\begin{cases}
2^n-1 & s = \varnothing\\
-1 & s \ne \varnothing\\
\end{cases}
\]
由于 \(g\) 的和为 \(0\),则 \(h\) 的和也为 \(0\),则 \(h_{\varnothing}\) 的值为 \(2^n-1\)。
所以,\(f*g=h\)。
所以,\(FWT(f)*FWT(g)=FWT(h)\)。
由于
\[FWT(g_s)=-1+\sum_{j=1}^{n}(-1)^{[j\in s]} p_j
\]
\[FWT(h_s)=
\begin{cases}
0 & s = \varnothing\\
2^n & s \ne \varnothing\\
\end{cases}
\]
因为如果 \(h_{\varnothing}=-1\),\(h_{s}=0\),所以现在,\(h_{s\ne \varnothing}=2^n\)。
\[FWT(f_s)=
\begin{cases}
1-\sum_{t}\frac{2^n}{1-\sum_{i}(-1)^{[i\in t]} p_i} & s = \varnothing\\
\frac{2^n}{-1+\sum_{i}(-1)^{[i\in S]} p_i} & s \ne \varnothing\\
\end{cases}
\]
有一个结论,\(\sum_{i} FWT_i(f)=2^n f_{\varnothing}\)。
所以,\(\sum_{i} FWT_i(f)=0\),于是计算出 \(f_{\varnothing}\)。
于是,得到答案。
\[\begin{aligned}
f_s&=IFWT_s(FWT(f))\\
&=\frac{1}{2^n}(f_{\varnothing}+\sum_{t\ne \varnothing} (-1)^{|s\cap t|}f_t)\\
&=\frac{1}{2^n}(\sum_{t\ne \varnothing} (-1+(-1)^{|s\cap t|})\frac{2^n}{-1+\sum_{i}(-1)^{[i\in s]} p_i})\\
&=\sum_{t\ne \varnothing} \frac{-2(|s\cap t| \bmod 2)}{-1+\sum_{i}(-1)^{[i\in s]} p_i}\\
&=\sum_{t\ne \varnothing} \frac{2(|s\cap t| \bmod 2)}{2\sum_{i}[i\in s] p_i}\\
&=\sum_{t\ne \varnothing} \frac{|s\cap t| \bmod 2}{\sum_{i\in s} p_i}\\
\end{aligned}
\]
然后 DP 计算即可。
时间复杂度 \(O(n\sum_i {p_i})\)。
代码
#include <bits/stdc++.h>
#define SZ(x) (int) x.size() - 1
#define all(x) x.begin(), x.end()
#define ms(x, y) memset(x, y, sizeof x)
#define F(i, x, y) for (int i = (x); i <= (y); i++)
#define DF(i, x, y) for (int i = (x); i >= (y); i--)
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
template <typename T> void chkmax(T& x, T y) { x = max(x, y); }
template <typename T> void chkmin(T& x, T y) { x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1; char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
const int N = 110, M = 50010, MOD = 998244353;
int n, dp[N][M][2], p[N], sum, ans;
bool s[N];
int power(int x, int y = MOD - 2) {
int ans = 1;
for (; y; x = (ll) x * x % MOD, y >>= 1)
if (y & 1) ans = (ll) ans * x % MOD;
return ans;
}
signed main() {
read(n);
F(i, 1, n) read(s[i]);
F(i, 1, n) read(p[i]), sum += p[i];
dp[0][0][0] = 1;
F(i, 1, n)
F(j, 0, sum)
F(k, 0, 1)
dp[i][j][k] = ((j >= p[i] ? dp[i - 1][j - p[i]][k ^ s[i]] : 0) + dp[i - 1][j][k]) % MOD;
F(i, 1, sum) ans = (ans + (ll) dp[n][i][1] * power(i)) % MOD;
cout << (ll) ans * sum % MOD;
return 0;
}