Wannafly Camp 2020 Day 1D 生成树 - 矩阵树定理,高斯消元
给出两幅 \(n(\leq 400)\) 个点的无向图 \(G_1 ,G_2\),对于 \(G_1\) 的每一颗生成树,它的权值定义为有多少条边在 \(G_2\) 中出现。求 \(G_1\) 所有生成树的权值和。
Solution
很容易想到,设 \(G_1\) 中每条边的权值,这条边在 \(G_2\) 中出现则权值为 \(1\),否则权值为 \(0\)。
现在就真的是求所有生成树的边权和的权值和了。
然而标准的 Matrix-Tree Theorem 求的是生成树的边权积的和。
现在我们定义每条只出现在 \(G_1\) 中的边边权为 \(1\),同时出现在 \(G_1,G_2\) 中的边权为 \(x\),则基尔霍夫矩阵的每个元素嗾使一个多项式,记为 \(B(x)\)。
\(\det B(x)\) 是一个 \(n-1\) 次多项式 \(f(x) = \sum a_i x^i\),那么其中 \(a_i\) 就是使用了 \(i\) 条公共变的生成树个数。
于是答案就是 \(f'(1)=\sum ia_i=\det B(1) \cdot \sum_i \sum_j (B^{-1}(1))_{i,j}\cdot B'(1)_{i,j}\)
于是用 Gauss 消元法求行列式和逆矩阵即可
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N = 405;
const int mod = 998244353;
namespace mat {
int f[N][N<<1],a[N][N],n;
inline void exgcd(int a,int b,int &x,int &y) {
    if(!b) {
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,x,y);
    int t=x;
    x=y,y=t-(a/b)*y;
}
inline int inv(int a,int b) {
    int x,y;
    return exgcd(a,b,x,y),(x%b+b)%b;
}
int getdet() {
    int det=1;
    int flag=0;
    for(int i=1; i<=n; i++) {
        for(int j=i+1; j<=n; j++) {
            int x=i,y=j;
            while(a[y][i]!=0) {
                int t=a[x][i]*inv(a[y][i],mod)%mod;
                for(int k=i; k<=n; k++) (a[x][k]-=t*a[y][k]%mod)%=mod;
                swap(x,y);
            }
            if(x!=i) {
                for(int k=1; k<=n; k++) {
                    swap(a[x][k],a[i][k]);
                }
                flag^=1;
            }
        }
        if(a[i][i]==0)  return 0;
        det=det*a[i][i]%mod;
    }
    if(flag) det=-det;
    det%=mod; det+=mod; det%=mod;
    return det;
}
int solve() {
    int m=n*2;
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) a[i][j]=f[i][j], f[i][j+n]=0;
    }
    int ret= getdet();
    for(int i=1; i<=n; ++i) {
        f[i][n+i]=1;
    }
    for(int i=1; i<=n; ++i) {
        for(int j=i; j<=n; j++)
            if(f[j][i]) {
                for(int k=1; k<=m; k++)
                    swap(f[i][k],f[j][k]);
                break;
            }
        if(!f[i][i]) {
            return 0;
        }
        int r=inv(f[i][i],mod);
        for(int j=i; j<=m; ++j)
            f[i][j]=f[i][j]*r%mod;
        for(int j=1; j<=n; ++j)
            if(j!=i) {
                r=f[j][i];
                for(int k=i; k<=m; ++k)
                    f[j][k]=(f[j][k]-r*f[i][k]%mod+mod)%mod;
            }
    }
    return ret;
}
}
int n,b[N][N],bd[N][N];
char g1[N][N],g2[N][N];
signed main() {
    cin>>n;
    for(int i=1;i<=n;i++) {
        cin>>g1[i]+1;
    }
    for(int i=1;i<=n;i++) {
        cin>>g2[i]+1;
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<i;j++) {
            if(g1[i][j]=='1') b[i][j]=-1, b[j][i]=-1, b[i][i]++, b[j][j]++;
            if(g1[i][j]=='1' && g2[i][j]=='1') bd[i][j]=-1, bd[j][i]=-1, bd[i][i]++, bd[j][j]++;
        }
    }
    for(int i=1;i<n;i++) {
        for(int j=1;j<n;j++) {
            mat::f[i][j]=b[i][j];
        }
    }
    --n;
    mat::n=n;
    int det=mat::solve();
    int ans=0;
    /*for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) cout<<b[i][j]<<" ";
        cout<<endl;
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) cout<<bd[i][j]<<" ";
        cout<<endl;
    }
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) cout<<mat::f[i][j+n]<<" ";
        cout<<endl;
    }*/
    for(int i=1;i<=n;i++) {
        for(int j=1;j<=n;j++) {
            ans+=mat::f[i][j+n]*bd[i][j];
            ans%=mod;
            ans+=mod;
            ans%=mod;
        }
    }
    //cout<<ans<<" "<<det<<endl;
    cout<<((ans*det)%mod+mod)%mod;
}
Wannafly Camp 2020 Day 1D 生成树 - 矩阵树定理,高斯消元的更多相关文章
- [spoj104][Highways] (生成树计数+矩阵树定理+高斯消元)
		In some countries building highways takes a lot of time... Maybe that's because there are many possi ... 
- BZOJ4031 [HEOI2015]小Z的房间  【矩阵树定理 + 高斯消元】
		题目链接 BZOJ4031 题解 第一眼:这不裸的矩阵树定理么 第二眼:这个模\(10^9\)是什么鬼嘛QAQ 想尝试递归求行列式,发现这是\(O(n!)\)的.. 想上高斯消元,却又处理不了逆元这个 ... 
- P3317 [SDOI2014]重建 变元矩阵树定理 高斯消元
		传送门:https://www.luogu.org/problemnew/show/P3317 这道题的推导公式还是比较好理解的,但是由于这个矩阵是小数的,要注意高斯消元方法的使用: #include ... 
- CF917D-Stranger Trees【矩阵树定理,高斯消元】
		正题 题目链接:https://www.luogu.com.cn/problem/CF917D 题目大意 给出\(n\)个点的一棵树,对于每个\(k\)求有多少个\(n\)个点的树满足与给出的树恰好有 ... 
- 洛谷4208 JSOI2008最小生成树计数(矩阵树定理+高斯消元)
		qwq 这个题目真的是很好的一个题啊 qwq 其实一开始想这个题,肯定是无从下手. 首先,我们会发现,对于无向图的一个最小生成树来说,只有当存在一些边与内部的某些边权值相同的时候且能等效替代的时候,才 ... 
- 【BZOJ3534】【Luogu P3317】 [SDOI2014]重建 变元矩阵树,高斯消元
		题解看这里,主要想说一下以前没见过的变元矩阵树还有前几个题见到的几个小细节. 邻接矩阵是可以带权值的.求所有生成树边权和的时候我们有一个基尔霍夫矩阵,是度数矩阵减去邻接矩阵.而所谓变元矩阵树实际上就是 ... 
- SP104 Highways (矩阵树,高斯消元)
		矩阵树定理裸题 //#include <iostream> #include <cstdio> #include <cstring> #include <al ... 
- 【bzoj2467】[中山市选2010]生成树  矩阵树定理
		题目描述 有一种图形叫做五角形圈.一个五角形圈的中心有1个由n个顶点和n条边组成的圈.在中心的这个n边圈的每一条边同时也是某一个五角形的一条边,一共有n个不同的五角形.这些五角形只在五角形圈的中心的圈 ... 
- Wannafly挑战赛23F-计数【原根,矩阵树定理,拉格朗日插值】
		正题 题目链接:https://ac.nowcoder.com/acm/contest/161/F 题目大意 给出\(n\)个点的一张图,求它的所有生成树中权值和为\(k\)的倍数的个数.输出答案对\ ... 
随机推荐
- 20191223-python学习第三天
			1.运算符补充 (1)in 与 not in 学习 (2)优先级 >小于 ,<小于,计算运算关系优先级 > not > and > or 2.charm自动生成文件头部 ... 
- PgSQL备份
			SQL转储. 这里我们用到的工具是pg_dump和pg_dumpall. 这种方式可以在数据库正在使用的时候进行完整一致的备份,并不阻塞其它用户对数据库的访问.它会产生一个脚本文件,里面包含备份开始时 ... 
- [CentOS7 mini]Linux命令补全 yum install bash-completion
			CentOS7 mini默认不带命令补全需要自行安装 使用国内yum清华源 安装完后退出当前窗口再登录生效 # yum install -y bash-completion 已加载插件:fastest ... 
- 不会用数据可视化大屏?一招教你轻松使用数据可视化BI软件创建农业公司运营数据分析大屏
			灯果数据可视化BI软件是新一代人工智能数据可视化大屏软件,内置丰富的大屏模板,可视化编辑操作,无需任何经验就可以创建属于你自己的大屏.大家可以在他们的官网下载软件. 本文以农业公司运营数据分析大屏 ... 
- C++ char to string 方法
			1. 使用string()构造函数方法 //method 1: the constructor of string() char c = 'F'; , c); cout << s ; 2. ... 
- Oracle导出警告“EXP-00003: 未找到段 (0,0) 的存储定义”解决
			环境:CentOS7.4 Oracle11.2.0.4(搭建rac集群) 问题描述:在使用exp命令执行导出的时候,部分表提示“EXP-00003: 未找到段 (0,0) 的存储定义”警告. 问题 ... 
- navicat连接异常 authentication plugin 'caching_sha2_password' 问题解决
			mysql 8.0 默认使用 caching_sha2_password 身份验证机制 -- 从原来的 mysql_native_password 更改为 caching_sha2_password. ... 
- Elasticsearch必知必会的干货知识一:ES索引文档的CRUD
			 若在传统DBMS 关系型数据库中查询海量数据,特别是模糊查询,一般我们都是使用like %查询的值%,但这样会导致无法应用索引,从而形成全表扫描效率低下,即使是在有索引的字段精确值查找,面对海量数 ... 
- xshell/secureCRT连接Linux及其常用命令
			一.xshell:在Windows界面下用来访问远端不同系统下的服务器,从而比较好的达到远程控制终端的目的 下载安装后连接步骤: 二.secureCRT:在Windows下登录UNIX或Linux服务 ... 
- 实验一Git代码版本管理
			GIT代码版本管理 实验目的: 1)了解分布式分布式版本控制系统的核心机理: 2) 熟练掌握git的基本指令和分支管理指令: 实验内容: 1)安装git 2)初始配置git ,git init git ... 
