位运算trick+树形 dp
看到题目中贡献的计算,可以想到乘法分配律,也就是一个连通块的乘积可以直接乘在当前所有方案的权值之和上。
可以考虑特殊性质:链。那么树的问题就变成了序列问题。容易设 \(f_i\) 表示 \(i\) 以前的节点的所有断边方案权值和。转移直接枚举断边:\(f_i=\sum f_j\times(s_i\oplus s_j)\)。\(s_i=\bigoplus\limits_{j=1}^i a_j\)。
复杂度是 \(O(n^2)\)。瓶颈在于断边的枚举,同时又注意到位运算的相关性质还没有用到,考虑这个方面的优化,一个经典 trick 就是按二进制位计算贡献,这样做的原理一个是位运算是按位计算,一个是答案的计算满足分配律。
可以设 \(g_{i,j,0/1}\) 表示考虑到第 \(i\) 个位置,与 \(i\) 相连的连通块在第 \(j\) 位二进制位上的值为 \(0/1\),并且强制 \(i\) 向后连边的断边方案权值和(不计算 \(i\) 的影响)。这样做的好处就是转移不再需要枚举断边。转移有:
\(g_{i,j,0}=g_{i,j,0}\times(f_{i-1}+g_{i-1,j,0})+g_{i,j,1}\times g_{i-1,j,1}\)
\(g_{i,j,1}=g_{i,j,1}\times(f_{i-1}+g_{i-1,j,0})+g_{i,j,0}\times g_{i-1,j,1}\)
\(f_{i}=\sum\limits_{j=0}^{63} 2^j\times g_{i,j,1}\)
实际上在 \(g\) 转移时,\(f_i\) 转移的就是 \(i\) 单独成为一个连通块的情况,而 \(g\) 转移的就是与前面的连通块相连时的贡献,可以发现这样的两种情况是不存在交集的。最后 \(f_i\) 的计算就是计算 \(i\) 所在连通块每一位上的贡献(与先前的枚举断边的方法等价),这里转换了计算贡献的角度。
考虑树上的做法,其实完全类似,就是把式子搬到树上,这里就不列举,重点还是序列问题时的思路。
具体在写转移的时候要注意把当前状态存起来。
复杂度 \(O(n\log V)\)。
#include <bits/stdc++.h>
#define pii std::pair<int, int>
#define fi first
#define se second
#define pb push_back
typedef long long i64;
const i64 iinf = 0x3f3f3f3f, linf = 0x3f3f3f3f3f3f3f3f;
const int N = 5e5 + 10, mod = 998244353;
int n;
i64 a[N];
i64 f[N];
int g[N][65][2];
std::vector<int> e[N];
void dfs(int u, int fa) {
for(int i = 0; i <= 63; i++) g[u][i][(a[u] >> i) & 1] = 1;
for(auto v : e[u]) {
if(v == fa) continue;
dfs(v, u);
for(int i = 0; i <= 63; i++) {
i64 u0 = g[u][i][0], u1 = g[u][i][1]; //先存起来,防止转移错误
g[u][i][0] = (u0 * (g[v][i][0] + f[v]) % mod + u1 * g[v][i][1] % mod) % mod;
g[u][i][1] = (u0 * g[v][i][1] % mod + u1 * (f[v] + g[v][i][0]) % mod) % mod;
}
}
for(int i = 0; i <= 63; i++) f[u] = (f[u] + (1ll << i) % mod * g[u][i][1]) % mod;
}
void Solve() {
std::cin >> n;
for(int i = 1; i <= n; i++) std::cin >> a[i];
for(int i = 2; i <= n; i++) {
int u;
std::cin >> u;
e[u].pb(i), e[i].pb(u);
}
dfs(1, 0);
std::cout << f[1] << "\n";
}
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
Solve();
return 0;
}
标签:P9745,06,int,枚举,times,i64,异或,断边,define
From: https://www.cnblogs.com/FireRaku/p/18146760