题解:P17781 千早爱音不是罪过
比较套路。
使用子集反演:设保留边集合为 \(S\),钦定 \(T\subseteq S\) 中的边保留,容斥系数为 \((-1)^{|S|-|T|}\)。因此问题可以转化为,给一部分边染成黑色或者白色,权值为将黑边保留后各连通块的点权异或和之积,乘上 \(-1\) 的白边数次方,求所有染色方案的权值和。
显然每个点至多向一个儿子连一条染色边,所有染色边形成若干条链,我们只需要把这些链缩起来再做拓扑序计数。
对于 \(u\) 子树内的一种染色方案,设将染色边缩起来后有 \(i\) 个点,有 \(c\) 种拓扑序,包含 \(u\) 的黑边连通块的异或和为 \(s\),其他黑边连通块的异或和之积乘上容斥系数为 \(w\)。设计 DP:令 \(f_{u,i}\) 表示 \(\sum wcs\),\(g_{u,i,k}\) 表示 \(\sum wc\operatorname{bit}_k(s)\),\(h_{u,i}\) 表示 \(\sum wc\),合并儿子节点时令 \(P_i\) 表示 \(h_{u,i}\) 中 \(u\) 没有向儿子节点连染色边的权值和。
考虑转移。设 \(u\) 所在部分缩点后有 \(i\) 个点,\(v\) 子树内有 \(j\) 个点。若 \((u,v)\) 不染色,则合并后有 \(i+j\) 个点,拓扑序方案数需要乘上 \(\dbinom{i+j-1}{j}\):
若 \((u,v)\) 染色,则 \(u\) 所在部分必须拿 \(P_i\) 来贡献。合并后有 \(i+j-1\) 个点,拓扑序方案数需要乘上 \(\dbinom{i+j-2}{j-1}\)。
对于 \(h\),若 \((u,v)\) 染成黑色则两个连通块合并,贡献 \(h_{v,j}\),若染成白色则贡献 \(-f_{v,j}\):
对于 \(g\),分讨 \(a_u\) 第 \(k\) 位的取值:
- 若第 \(k\) 位为 \(0\),将 \((u,v)\) 染成黑色会使这一位取 \(v\) 所在连通块的对应位,染成白色没有贡献:\[g'_{u,i+j-1,k}\gets P_ig_{v,j,k}\dbinom{i+j-2}{j-1} \]
- 若第 \(k\) 位为 \(1\),将 \((u,v)\) 染成黑色时会翻转 \(v\) 所在连通块的对应位,贡献为 \(h_{v,j}-g_{v,j,k}\),染成白色时贡献为 \(-f_{v,j}\):\[g'_{u,i+j-1,k}\gets P_i(h_{v,j}-g_{v,j,k}-f_{v,j})\dbinom{i+j-2}{j-1} \]
合并完所有儿子后,令 \(f_{u,i}=\sum_k g_{u,i,k}2^k\) 即可。
时间复杂度为 \(\mathcal{O}(n^2\log{V})\)。
主要代码
int n;
ull a[MAXN];
vector<int> T[MAXN];
mint C[MAXN][MAXN];
vector<mint> f[MAXN], h[MAXN];
vector<array<mint, 64>> g[MAXN];
void init(int n) {
for (int i = 0; i <= n; ++i) {
for (int j = 0; j <= i; ++j) {
C[i][j] = !j ? 1 : C[i - 1][j - 1] + C[i - 1][j];
}
}
}
void dfs(int u, int fu) {
vector<mint> p(2);
h[u].resize(2);
g[u].resize(2);
p[1] = h[u][1] = 1;
for (int k = 0; k < 64; ++k) g[u][1][k] = a[u] >> k & 1;
int szu = 1;
for (int v : T[u]) {
if (v == fu) continue;
dfs(v, u);
int szv = f[v].size() - 1;
vector<mint> nh(szu + szv + 1), np(szu + szv + 1);
vector<array<mint, 64>> ng(szu + szv + 1);
for (int i = 1; i <= szu; ++i) {
for (int j = 1; j <= szv; ++j) {
np[i + j] += p[i] * f[v][j] * C[i + j - 1][j];
nh[i + j] += h[u][i] * f[v][j] * C[i + j - 1][j];
nh[i + j - 1] += p[i] * (h[v][j] - f[v][j]) * C[i + j - 2][j - 1];
for (int k = 0; k < 64; ++k) {
ng[i + j][k] += g[u][i][k] * f[v][j] * C[i + j - 1][j];
if (a[u] >> k & 1) ng[i + j - 1][k] += p[i] * (h[v][j] - g[v][j][k] - f[v][j]) * C[i + j - 2][j - 1];
else ng[i + j - 1][k] += p[i] * g[v][j][k] * C[i + j - 2][j - 1];
}
}
}
nh.swap(h[u]);
np.swap(p);
ng.swap(g[u]);
szu += szv;
}
f[u].resize(szu + 1);
for (int i = 1; i <= szu; ++i) {
for (int k = 0; k < 64; ++k) {
f[u][i] += g[u][i][k] * (1ull << k);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n;
for (int i = 1; i <= n; ++i) cin >> a[i];
for (int i = 1; i < n; ++i) {
int u, v;
cin >> u >> v;
T[u].emplace_back(v);
T[v].emplace_back(u);
}
init(n);
dfs(1, 0);
mint ans = 0;
for (int i = 1; i <= n; ++i) ans += f[1][i];
cout << ans;
return 0;
}

浙公网安备 33010602011771号