CF1299D Around the World【线性基,dp】
给定 \(n\) 个点 \(m\) 条边的简单无向连通图,每条边有边权。求使得不存在包含 \(1\) 的环经过至少一条边奇数次且经过的所有边权(经过多次算多次)异或和为 \(0\) 的删除若干条与 \(1\) 相连的边的方案数模 \(10^9+7\) 的值。
\(n,m\le 10^5\),边权 \(<2^5\),不存在包含 \(1\) 的长度 \(>3\) 的简单环。
题目里的条件即为环边权异或和线性无关。
由于边权很小,所以线性基(线性空间)也很少,只有 \(\sum \binom 5k_2=374\) 个。
对去掉 \(1\) 之后的每个连通块单独计算。显然对于每个连通块,与 \(1\) 相连的点至多只有 \(2\) 个,且如果有两个则其之间必定有边。
把线性基塞进状态做 dp,先预处理出线性基的编号,再预处理出线性基合并的编号,转移枚举与 \(1\) 相连的边是否断开即可。
时间复杂度 \(O((cw)^2+cn)\),其中 \(w=5\) 是位数,\(c=374\) 是线性空间数量。
#include<bits/stdc++.h>
using namespace std;
const int N = 100003, M = 374, mod = 1e9 + 7, lb[M] = {0,1,5,37,549,16933,16421,24613,517,16901,20997,773,17157,21253,16389,20485,24581,28677,33,545,16929,18977,673,17057,19105,16417,18465,24609,26657,49,561,16945,18993,689,17073,19121,16433,18481,24625,26673,513,16897,18945,20993,23041,641,17025,19073,21121,23169,769,17153,19201,21249,23297,897,17281,19329,21377,23425,16385,18433,20481,22529,24577,26625,28673,30721,4,36,548,16932,17956,612,16996,18020,16420,17444,24612,25636,44,556,16940,17964,620,17004,18028,16428,17452,24620,25644,516,16900,17924,20996,22020,580,16964,17988,21060,22084,772,17156,18180,21252,22276,836,17220,18244,21316,22340,16388,17412,20484,21508,24580,25604,28676,29700,6,38,550,16934,17958,614,16998,18022,16422,17446,24614,25638,46,558,16942,17966,622,17006,18030,16430,17454,24622,25646,518,16902,17926,20998,22022,582,16966,17990,21062,22086,774,17158,18182,21254,22278,838,17222,18246,21318,22342,16390,17414,20486,21510,24582,25606,28678,29702,32,544,16928,17952,18976,20000,608,16992,18016,19040,20064,672,17056,18080,19104,20128,736,17120,18144,19168,20192,16416,17440,18464,19488,24608,25632,26656,27680,40,552,16936,17960,18984,20008,616,17000,18024,19048,20072,680,17064,18088,19112,20136,744,17128,18152,19176,20200,16424,17448,18472,19496,24616,25640,26664,27688,48,560,16944,17968,18992,20016,624,17008,18032,19056,20080,688,17072,18096,19120,20144,752,17136,18160,19184,20208,16432,17456,18480,19504,24624,25648,26672,27696,56,568,16952,17976,19000,20024,632,17016,18040,19064,20088,696,17080,18104,19128,20152,760,17144,18168,19192,20216,16440,17464,18488,19512,24632,25656,26680,27704,512,16896,17920,18944,19968,20992,22016,23040,24064,576,16960,17984,19008,20032,21056,22080,23104,24128,640,17024,18048,19072,20096,21120,22144,23168,24192,704,17088,18112,19136,20160,21184,22208,23232,24256,768,17152,18176,19200,20224,21248,22272,23296,24320,832,17216,18240,19264,20288,21312,22336,23360,24384,896,17280,18304,19328,20352,21376,22400,23424,24448,960,17344,18368,19392,20416,21440,22464,23488,24512,16384,17408,18432,19456,20480,21504,22528,23552,24576,25600,26624,27648,28672,29696,30720,31744};
template<typename T>
void read(T &x){
int ch = getchar(); x = 0;
for(;ch < '0' || ch > '9';ch = getchar());
for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
} void qmo(int &x){x += x >> 31 & mod;}
struct LB {
int val[5];
LB(int x = 0){
val[0] = x&1; val[1] = x>>1&3; val[2] = x>>3&7;
val[3] = x>>6&15; val[4] = x>>10&31;
}
bool ins(int x){
for(int i = 4;~i;-- i) if(x>>i&1){
if(!val[i]){
val[i] = x;
for(int j = i-1;~j;-- j)
if(val[j] && (val[i]>>j&1)) val[i] ^= val[j];
for(int j = i+1;j < 5;++ j)
if(val[j]>>i&1) val[j] ^= val[i];
return true;
} x ^= val[i];
} return false;
}
int atoi() const {
return val[0] | val[1]<<1 | val[2]<<3 | val[3]<<6 | val[4]<<10;
}
} B[N];
int n, m, cnt, bct, tim, head[N], to[N<<1], nxt[N<<1], w[N<<1], trs[M][M], id[1<<15], bel[N], rt[N], val[N], dis[N], dfn[N], f[M], g[M], ans;
bool has[N], ok[N];
void add(int u, int v, int c){
to[++cnt] = v; nxt[cnt] = head[u]; head[u] = cnt; w[cnt] = c;
}
void dfs(int x, int fa){
dfn[x] = ++tim; int now = bel[x];
for(int i = head[x];i;i = nxt[i]){
int v = to[i];
if(!bel[v]){bel[v] = now; dis[v] = dis[x] ^ w[i]; dfs(v, x);}
else if(v != fa && v != 1 && dfn[v] < dfn[x])
ok[now] &= B[now].ins(dis[v] ^ dis[x] ^ w[i]);
}
}
int main(){
read(n); read(m); memset(trs, -1, sizeof trs);
for(int i = 1, a, b, c;i <= m;++ i){
read(a); read(b); read(c);
add(a, b, c); add(b, a, c);
} trs[0][0] = 0;
for(int i = 0;i < M;++ i) id[lb[i]] = i;
for(int i = 0;i < M;++ i){
LB l1(lb[i]);
for(int j = 0;j < i;++ j) trs[i][j] = trs[j][i];
for(int j = i+1;j < M;++ j){
LB l2(lb[j]); bool suc = true;
for(int k = 0;k < 5;++ k)
if(l1.val[k]) suc &= l2.ins(l1.val[k]);
if(suc) trs[i][j] = id[l2.atoi()];
}
} memset(ok, 1, sizeof ok); bel[1] = -1;
for(int i = head[1];i;i = nxt[i]){
int v = to[i];
if(!bel[v]){
rt[++bct] = v; val[bct] = w[i];
bel[v] = bct; dfs(v, 1);
} else {
int _ = rt[bel[v]];
for(int j = head[v];j;j = nxt[j]) if(to[j] == _){
val[bel[v]] ^= w[i] ^ w[j];
has[bel[v]] = true; break;
}
}
} f[0] = 1;
for(int i = 1;i <= bct;++ i) if(ok[i]){
memcpy(g, f, sizeof f);
if(has[i]){
int lb1 = id[B[i].atoi()];
LB _1 = B[i]; bool flg = _1.ins(val[i]);
int lb2 = id[_1.atoi()];
for(int j = 0;j < M;++ j){
if(~trs[j][lb1]){
int &u = f[trs[j][lb1]], v = g[j] - mod;
qmo(u += v); qmo(u += v);
} if(flg && ~trs[j][lb2]) qmo(f[trs[j][lb2]] += g[j] - mod);
}
} else {
int lb1 = id[B[i].atoi()];
for(int j = 0;j < M;++ j)
if(~trs[j][lb1]) qmo(f[trs[j][lb1]] += g[j] - mod);
}
}
for(int i = 0;i < M;++ i) qmo(ans += f[i] - mod);
printf("%d\n", ans);
}