题解:CF724G Xor-matic Number of the Graph
节选自:线性代数学习笔记(二):线性基
我们先不考虑这道题是在图上操作,因此我们先来求不同异或和的和。
由于线性基中任意一组基异或起来都互不相同,这大大简化了这个问题,我们只需要统计即可,不需要考虑去重。
我们考虑按位算贡献。假设线性基中有 \(tot\) 个基,其中有 \(k (k > 0)\) 个基的第 \(i\) 位为 \(1\),那么就有 \(tot - k\) 个第 \(i\) 位为 \(0\) 的基。这些第 \(i\) 位为 \(0\) 的基无论选不选都对答案不造成贡献,因此最终这一位的答案一定会乘以 \(2^{tot - k}\)。
现在我们考虑第 \(i\) 位为 \(1\) 的 \(k\) 个基,只有当从中选出奇数个基时,才会在这一位上留下一个 \(1\),因此答案是 \(\displaystyle\sum_{0 \leq j \leq k \wedge j \bmod 2 = 1} \binom kj\)。
我们考虑二项式定理 \((x + y)^k = \displaystyle\sum_{0 \leq j \leq k} \binom kj x^j y^{k - j}\),由于 \(k > 0\),我们把 \(x, y\) 带成 \(-1\) 和 \(1\),那么 \(0 = \displaystyle\sum_{0 \leq j \leq k} \binom kj (-1)^j\),这个式子在 \(j\) 为偶数时为正,\(j\) 为奇数时为负,于是 \(\displaystyle\sum_{0 \leq j \leq k \wedge j \bmod 2 = 1} \binom kj = \sum_{0 \leq j \leq k \wedge j \bmod 2 = 0} \binom kj\)。
因为组合数一行之和 \(\displaystyle 2^k\),那么 \(\displaystyle\sum_{0 \leq j \leq k \wedge j \bmod 2 = 1} \binom kj = 2^{k - 1}\),于是这一位的答案就是 \(2^{tot - 1}\)。
很显然,如果 \(k\) 为 \(0\) 那么答案就是 \(0\),因此如果存在一个最高位为 \(i\) 的基,那么答案就会乘以 \(2^{tot - 1}\),那么答案就是 \(\displaystyle\prod_{i = 0}^{\log n} 2^{tot - 1} [w_i \neq 0]\)。
回到这道题目,我们需要求不同的路径异或和的和。参考例题十一,我们把所有环插入线性基中,再找到一条主路径,那么最终答案就是线性基中的答案异或上主路径长度,但 \(u\) 和 \(v\) 都是不固定的,如果一对一对枚举,复杂度直接炸了,考虑如何优化。
还是考虑异或相等为 \(0\) 的情况。如果我们随便找一个点作为起点,记录到 \(u\) 的距离 \(dis_u\) 和到 \(v\) 的距离 \(dis_v\),那么 \(u\) 到 \(v\) 的距离就是 \(dis_u \operatorname{xor} dis_v\)。
那么现在问题就变成了在集合 \(\{dis_i\}\),中任意选两个数字 \(dis_u, dis_v\),我们求出线性基中异或和的和,再异或上 \(dis_u\) 和 \(dis_v\),加入到答案中就行了。但这样复杂度依然爆炸。
我们继续考虑按位贡献,我们知道线性基如果有一个数第 \(i\) 位上是 \(1\),那么这一位上就有 \(2^{tot - 1}\) 种方式凑出 \(1\),\(2^{tot - 1}\) 种方式凑出 \(0\)。因此无论 \(\{dis_i\}\) 中选出两个数的异或和的第 \(i\) 位为 \(1\) 或者 \(0\),对答案的贡献都是 \(2^{tot - 1}\)。假设 \(\{dis_i\}\) 的大小为 \(siz\),那么总贡献就是 \(2^{tot - 1} \times \displaystyle\frac{siz(siz - 1)}{2}\)。
如果线性基中没有数字第 \(i\) 位上是 \(1\),那么无论多少个数异或起来都是 \(0\),因此答案需要乘以 \(2^{tot}\)。其次选出的 \(dis_u\) 和 \(dis_v\) 的第 \(i\) 位上必须一个是 \(0\),一个是 \(1\)。我们假设 \(\{dis_i\}\) 中有 \(cnt\) 个数字第 \(i\) 位上为 \(1\),那么对于答案的贡献就是 \(2^{tot} \times cnt \times (siz - cnt)\)。
最后,这道题的图可能不联通,每个连通块分开算即可。
点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5 + 9, M = 2e5 + 9, MOD = 1e9 + 7;
struct Edge{
int v, w, nex;
} e[M << 1];
int head[N], ecnt;
void addEdge(int u, int v, int w){
e[++ecnt] = Edge{v, w, head[u]};
head[u] = ecnt;
}
int qpow(int a, int b){
int res = 1;
while(b > 0){
if(b & 1)
res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}
int dis[N], n, m, ans, sum;
vector <int> vec;
bool vis[N];
struct Basis{
int w[69], tot;
void clear(){
memset(w, 0, sizeof(w));
tot = 0;
}
void insert(int x){
for(int i = 62; ~i; i--){
if(x >> i & 1ll){
if(w[i])
x ^= w[i];
else {
w[i] = x;
tot++;
break;
}
}
}
}
int calc(){
int sum = 0, res = 0, siz = vec.size();
for(int i = 62; ~i; i--)
sum |= w[i];
for(int i = 62; ~i; i--){
int cnt = 0;
for(int j = 0; j < siz; j++)
if(vec[j] >> i & 1ll)
cnt++;
if(sum >> i & 1ll)
res = (res + qpow(2, i) % MOD * qpow(2, tot - 1) % MOD * (siz * (siz - 1) / 2 % MOD) % MOD) % MOD;
else
res = (res + qpow(2, i) % MOD * qpow(2, tot) % MOD * cnt % MOD * (siz - cnt) % MOD) % MOD;
}
return res;
}
} b;
void dfs(int u){
vis[u] = true;
vec.push_back(dis[u]);
for(int i = head[u]; i; i = e[i].nex){
int v = e[i].v;
if(vis[v])
b.insert(dis[u] ^ dis[v] ^ e[i].w);
else {
dis[v] = dis[u] ^ e[i].w;
dfs(v);
}
}
}
signed main(){
scanf("%lld%lld", &n, &m);
for(int i = 1; i <= m; i++){
int u, v, w;
scanf("%lld%lld%lld", &u, &v, &w);
addEdge(u, v, w);
addEdge(v, u, w);
}
for(int i = 1; i <= n; i++){
if(!vis[i]){
b.clear();
vec.clear();
dfs(i);
ans = (ans + b.calc()) % MOD;
}
}
printf("%lld", ans);
return 0;
}
本文来自博客园,作者:Orange_new,转载请注明原文链接:https://www.cnblogs.com/JPGOJCZX/p/18790558

浙公网安备 33010602011771号