题目传送门

  戳我来传送

题目大意

  给定一个图,问它的所有生成树的边权的最大公约数之和。

  可以考虑计算边权的最大公约数为$i$的生成树的个数$f(i)$,最后累加答案。

  然后考虑这样的生成树的个数怎么求,根据某个经典套路,我们可以容斥。

  因为可以求出边权的最大公约数为$i$的倍数的生成树的个数$F(i)$,所以减去它的倍数的$f$就是$f(i)$了。

  但是这么做会T掉。

  可以用$O(W\log W)$的时间内预处理出为边权$i$的倍数的边数有多少条。然后高消前判断一下边数是否大于等于$n - 1$。

  具体有关时间复杂度的证明可以在洛谷的题解中找到,这里就不给出了。

Code

 /**
* luogu
* Problem#3790
* Accepted
* Time: 6016ms
* Memory: 9402k
*/
#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;
typedef bool boolean;
#define ll long long const int N = , M = 1e9 + ; void exgcd(int a, int b, int& d, int& x, int& y) {
if(!b)
d = a, x = , y = ;
else {
exgcd(b, a % b, d, y, x);
y -= (a / b) * x;
}
} int inv(int a, int n) {
int d, x, y;
exgcd(a, n, d, x, y);
return (x < ) ? (x + n) : (x);
} typedef class Matrix {
public:
int a[N][N]; void reset() {
memset(a, , sizeof(a));
} int det(int n) {
int pro = ;
for (int i = , e; i <= n; i++) {
e = ;
for (int j = i; j <= n && !e; j++)
if (a[j][i])
e = j;
if (e == ) return ;
if (e != i)
for (int j = ; j <= n; j++)
swap(a[e][j], a[i][j]);
for (int j = , x, y; j <= n; j++) {
if (j == i) continue;
x = a[i][i], y = a[j][i], pro = pro * 1ll * x % M;
for (int k = ; k <= n; k++) {
a[j][k] = (a[j][k] * 1ll * x - a[i][k] * 1ll * y) % M;
if (a[j][k] < ) a[j][k] += M;
} }
}
int rt = inv(pro, M);
for (int i = ; i <= n; i++)
rt = rt * 1ll * a[i][i] % M;
return rt;
}
}Matrix; typedef class Edge {
public:
int u, v, w;
}Edge; const int Val = 1e6 + ; int n, m;
Edge* es;
Matrix a;
int ce[Val], f[Val]; inline void init() {
scanf("%d%d", &n, &m);
es = new Edge[(m + )];
for (int i = ; i <= m; i++)
scanf("%d%d%d", &es[i].u, &es[i].v, &es[i].w), ce[es[i].w]++;
} int calc(int g) {
if (ce[g] < n - ) return ;
a.reset();
for (int i = , u, v; i <= m; i++)
if (!(es[i].w % g)) {
u = es[i].u - , v = es[i].v - ;
a.a[u][u]++, a.a[v][v]++;
a.a[u][v]--, a.a[v][u]--;
if (a.a[u][v] < ) a.a[u][v] += M;
if (a.a[v][u] < ) a.a[v][u] += M;
}
int rt = a.det(n - );
// cerr << rt << endl;
return rt;
} int res = ;
inline void solve() {
for (int i = ; i < Val; i++)
for (int j = (i << ); j < Val; j += i)
ce[i] += ce[j];
for (int i = Val - ; i; i--) {
f[i] = calc(i);
for (int j = (i << ); j < Val; j += i) {
f[i] -= f[j];
if (f[i] < )
f[i] += M;
}
res = (res + f[i] * 1ll * i) % M;
}
printf("%d", res);
} int main() {
init();
solve();
return ;
}

luogu 3790 文艺数学题 - 矩阵树定理 - 容斥原理的更多相关文章

  1. Luogu P4336 [SHOI2016]黑暗前的幻想乡 矩阵树定理+容斥原理

    真是菜到爆炸....容斥写反(反正第一次写qwq) 题意:$n-1$个公司,每个公司可以连一些边,求每个边让不同公司连的生成树方案数. 矩阵树定理+容斥原理(注意到$n$不是很大) 枚举公司参与与否的 ...

  2. 【bzoj4596】[Shoi2016]黑暗前的幻想乡 容斥原理+矩阵树定理

    题目描述 给出 $n$ 个点和 $n-1$ 种颜色,每种颜色有若干条边.求这张图多少棵每种颜色的边都出现过的生成树,答案对 $10^9+7$ 取模. 输入 第一行包含一个正整数 N(N<=17) ...

  3. bzoj 4596: [Shoi2016]黑暗前的幻想乡【容斥原理+矩阵树定理】

    真是简单粗暴 把矩阵树定理的运算当成黑箱好了反正我不会 这样我们就可以在O(n^3)的时间内算出一个无向图的生成树个数了 然后题目要求每个工程队选一条路,这里可以考虑容斥原理:全选的方案数-不选工程队 ...

  4. BZOJ 4766: 文艺计算姬 [矩阵树定理 快速乘]

    传送门 题意: 给定一个一边点数为n,另一边点数为m,共有n*m条边的带标号完全二分图$K_{n,m}$ 求生成树个数 1 <= n,m,p <= 10^18 显然不能暴力上矩阵树定理 看 ...

  5. 【BZOJ 4596】 4596: [Shoi2016]黑暗前的幻想乡 (容斥原理+矩阵树定理)

    4596: [Shoi2016]黑暗前的幻想乡 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 324  Solved: 187 Description ...

  6. 【Luogu】P3317重建(高斯消元+矩阵树定理)

    题目链接 因为这个专门跑去学了矩阵树定理和高斯消元qwq 不过不是很懂.所以这里只放题解 玫葵之蝶的题解 某未知dalao的矩阵树定理 代码 #include<cstdio> #inclu ...

  7. 【BZOJ4596】【Luogu P4336】 [SHOI2016]黑暗前的幻想乡 矩阵树定理,容斥

    同样是矩阵树定理的裸题.但是要解决它需要能够想到容斥才可以. \(20\)以内的数据范围一定要试试容斥的想法. #include <bits/stdc++.h> using namespa ...

  8. 【BZOJ4596】[Shoi2016]黑暗前的幻想乡 容斥+矩阵树定理

    [BZOJ4596][Shoi2016]黑暗前的幻想乡 Description 幽香上台以后,第一项措施就是要修建幻想乡的公路.幻想乡有 N 个城市,之间原来没有任何路.幽香向选民承诺要减税,所以她打 ...

  9. 洛谷 P4336 黑暗前的幻想乡 —— 容斥+矩阵树定理

    题目:https://www.luogu.org/problemnew/show/P4336 当作考试题了,然而没想出来,呵呵. 其实不是二分图完美匹配方案数,而是矩阵树定理+容斥... 就是先放上所 ...

随机推荐

  1. 微信支付相关js

    import $ from "jquery" /*支付功能开始*/let ip="";let nonceStr;let appId;let mchId;let ...

  2. cocos2d JS-(JavaScript) 使用特权方法的例子

    function User(name,age) { var year = (new Date()).getFullYear() - age; this.getYearBorn = function ( ...

  3. cookie和session必须了解的东西

    Cookie的机制 Cookie是浏览器(User Agent)访问一些网站后,这些网站存放在客户端的一组数据,用于使网站等跟踪用户,实现用户自定义功能. Cookie的Domain和Path属性标识 ...

  4. Eclipse 在Debug调试中用到的快捷键

    作用域 功能 快捷键 全局 单步返回 F7 全局 单步跳过 F6 全局 单步跳入 F5 全局 单步跳入选择 Ctrl+F5 全局 调试上次启动 F11 全局 继续 F8 全局 使用过滤器单步执行 Sh ...

  5. Debug常用命令

    R命令 查看.修改CPU中寄存器的值 -r ;查看寄存器的值 -r cs ;修改cs寄存器的值 D命令 查看内存中的内容 ;d 段地址:偏移地址 -d 1000:01 ;查看内存100001处的内容 ...

  6. ReactiveCocoa(III)

    flatMap(FlattenStrategy.latest) observe(on: UIScheduler()).startWithResult 切换线程: observeOn(UISchedul ...

  7. 运用kNN算法识别潜在续费商家

    背景与目标 Youzan 是一家SAAS公司,服务于数百万商家,帮助互联网时代的生意人私有化顾客资产.拓展互联网客群.提高经营效率.现在,该公司希望能够从商家的交易数据中,挖掘出有强烈续费倾向的商家, ...

  8. linux常用命令:touch 命令

    linux的touch命令不常用,一般在使用make的时候可能会用到,用来修改文件时间戳,或者新建一个不存在的文件. 1.命令格式: touch [选项]... 文件... 2.命令参数: -a    ...

  9. 如何干净卸载mysql

    一.在控制面板中卸载mysql软件: 二.卸载过后删除C:\Program Files (x86)\MySQL该目录下剩余了所有文件,把mysql文件夹也删了: 三.windows+R运行“reged ...

  10. Compare AURO OtoSys IM100 with OtoSys IM600

    The main difference lies in Mercedes-Benz, VW, Audi software and adapters to work with. Software dif ...