Codeforces 1218D Xor Spanning Tree FWT

根据题目描述可知是个特殊的仙人掌, 然后把环扣出来fwt算方案数就好了。

#include<bits/stdc++.h>
#define fi first
#define se second
#define mk make_pair
#define PII pair<int, int>
using namespace std;

const int N = 1 << 17;
const int mod = (int)1e9 + 7;
const int mod2 = 998244353;

int n, m, xr, fa[N], fa_w[N];
int dfn[N], dfs_clock;
vector<PII> G[N];
vector<vector<int>> VV;

int a[N], b[N], c[N], d[N];

void dfs(int u, int pa) {
    dfn[u] = ++dfs_clock;
    for(auto &e : G[u]) {
        int v = e.se, w = e.fi;
        if(v == pa) continue;
        if(!dfn[v]) {
            fa[v] = u, fa_w[v] = w;
            dfs(v, u);
        }
        else if(dfn[v] > dfn[u]) {
            vector<int> V;
            int cur_xr = w;
            for(int cur = v; cur != u; cur = fa[cur]) {
                cur_xr ^= fa_w[cur];
            }
            V.push_back(cur_xr ^ w);
            for(int cur = v; cur != u; cur = fa[cur]) {
                V.push_back(cur_xr ^ fa_w[cur]);
            }
            xr ^= cur_xr;
            VV.push_back(V);
        }
    }
}

void fwt_xor(int *a, int n, int dft, int mod, int inv2) {
    for(int i = 1; i < n; i <<= 1) {
        for(int j = 0; j < n; j += i << 1) {
            for(int k = j; k < j + i; k++) {
                int x = a[k], y = a[i + k];
                a[k] = (x + y) % mod; a[i + k] = (x - y + mod) % mod;
                if(dft == -1) a[k] = 1LL * a[k] * inv2 % mod, a[i + k] = 1LL * a[i + k] * inv2 % mod;
            }
        }
    }
}

int main() {
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= m; i++) {
        int u, v, w;
        scanf("%d%d%d", &u, &v, &w);
        G[u].push_back(mk(w, v));
        G[v].push_back(mk(w, u));
        xr ^= w;
    }
    dfs(1, 0);
    a[xr] = 1;
    c[xr] = 1;
    fwt_xor(a, 1 << 17, 1, mod, (mod + 1) >> 1);
    fwt_xor(c, 1 << 17, 1, mod2, (mod2 + 1) >> 1);
    for(auto &V : VV) {
        memset(b, 0, sizeof(b));
        memset(d, 0, sizeof(c));
        for(auto &t : V) b[t]++, d[t]++;
        fwt_xor(b, 1 << 17, 1, mod, (mod + 1) >> 1);
        fwt_xor(d, 1 << 17, 1, mod2, (mod2 + 1) >> 1);
        for(int i = 0; i < (1 << 17); i++) {
            a[i] = 1LL * a[i] * b[i] % mod;
            c[i] = 1LL * c[i] * d[i] % mod2;
        }
    }
    fwt_xor(a, 1 << 17, -1, mod, (mod + 1) >> 1);
    fwt_xor(c, 1 << 17, -1, mod2, (mod2 + 1) >> 1);
    for(int i = 0; i < (1 << 17); i++) {
        if(a[i] || c[i]) {
            printf("%d %d\n", i, a[i]);
            return 0;
        }
    }
    return 0;
}

/**
**/

原文地址:https://www.cnblogs.com/CJLHY/p/11719574.html

时间: 2024-10-29 07:56:44

Codeforces 1218D Xor Spanning Tree FWT的相关文章

Codeforces 618D Hamiltonian Spanning Tree(树的最小路径覆盖)

题意:给出一张完全图,所有的边的边权都是 y,现在给出图的一个生成树,将生成树上的边的边权改为 x,求一条距离最短的哈密顿路径. 先考虑x>=y的情况,那么应该尽量不走生成树上的边,如果生成树上有一个点的度数是n-1,那么必然需要走一条生成树上的边,此时答案为x+y*(n-2). 否则可以不走生成树上的边,则答案为y*(n-1). 再考虑x<y的情况,那么应该尽量走生成树上的边,由于树上没有环,于是我们每一次需要走树的一条路,然后需要从非生成树上的边跳到树的另一个点上去, 显然跳的越少越好,于

CodeForces 618D Hamiltonian Spanning Tree

题意:要把所有的节点都访问一次,并且不能重复访问,有两种方式访问,一种是根据树上的路径 走和当前节点连接的下一个节点cost x, 或者可以不走树上边,直接跳到不与当前节点连接的节点,cost y 分析: 别被树吓着! 一定会走n-1条路,那么就是有一些走树上的边,有一些不走. 如果树上的路径cost更大(x >= y),那么尽可能的不走树上的路径,那么根据尝试可以找到规律 如果有一个节点是所有节点的父节点,也就是说这个节点的度为n-1,那么只会走一个x其他都是y 如果没有这个节点,一定可以全部

hdu 4896 Minimal Spanning Tree

Minimal Spanning Tree Time Limit: 12000/6000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 144    Accepted Submission(s): 44 Problem Description Given a connected, undirected, weight graph G, your task is to select

HDU 4896 Minimal Spanning Tree(矩阵快速幂)

题意: 给你一幅这样子生成的图,求最小生成树的边权和. 思路:对于i >= 6的点连回去的5条边,打表知907^53 mod 2333333 = 1,所以x的循环节长度为54,所以9个点为一个循环,接下来的9个点连回去的边都是一样的.预处理出5个点的所有连通状态,总共只有52种,然后对于新增加一个点和前面点的连边状态可以处理出所有状态的转移.然后转移矩阵可以处理出来了,快速幂一下就可以了,对于普通的矩阵乘法是sigma( a(i, k) * b(k, j) ) (1<=k<=N), 现在

【HDU 4408】Minimum Spanning Tree(最小生成树计数)

Problem Description XXX is very interested in algorithm. After learning the Prim algorithm and Kruskal algorithm of minimum spanning tree, XXX finds that there might be multiple solutions. Given an undirected weighted graph with n (1<=n<=100) vertex

BNUOJ 26229 Red/Blue Spanning Tree

Red/Blue Spanning Tree Time Limit: 2000ms Memory Limit: 131072KB This problem will be judged on HDU. Original ID: 426364-bit integer IO format: %I64d      Java class name: Main Given an undirected, unweighted, connected graph, where each edge is colo

HDOJ 题目4408 Minimum Spanning Tree(Kruskal+Matrix_Tree)

Minimum Spanning Tree Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1408    Accepted Submission(s): 450 Problem Description XXX is very interested in algorithm. After learning the Prim algori

Codeforces 461B Appleman and Tree(木dp)

题目链接:Codeforces 461B Appleman and Tree 题目大意:一棵树,以0节点为根节点,给定每一个节点的父亲节点,以及每一个点的颜色(0表示白色,1表示黑色),切断这棵树的k条边,使得树变成k+1个联通分量.保证每一个联通分量有且仅有1个黑色节点.问有多少种切割方法. 解题思路:树形dp,dp[i][0]和dp[i][1]分别表示子树一下的切割方法中,i节点所在联通块不存在黑节点和已经存在一个黑节点的方案数. #include <cstdio> #include &l

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l