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);
}
posted @ 2021-04-21 15:39  mizu164  阅读(94)  评论(0编辑  收藏  举报