Description

Input

Output

HINT

题解:

一种很直观的想法是通过矩阵生成树求树形图方法数ans以及不包含某一条边i的树形图方法数ans[i],则答案为Σ(ans-ans[i])*w[i]。

对于树形图,矩阵生成树的建立方法是:将有向边(u,v)加入,即inc(A[u,u])(如果是要求n能够走到所有点则inc(A[v,v])),dec(A[u,v])。

删去第n行与第n列后,求行列式(即m[n,n],m为余子式矩阵)。

对于要删去某条边情况下的m[n,n],只要修改矩阵的两项,再求m[n,n]。因为总要删去第n行与第n列,所以只要保留(n-1)*(n-1)的矩阵,每次求整个矩阵的行列式即可。

但是这样做肯定会TLE,考虑使用伴随矩阵去优化。

有公式:

其中,A为原矩阵,A*为A的伴随矩阵,即A的代数余子式矩阵cof A的转置。(cof A[i,j]=(-1)^(i+j)*m[i,j])

我们通过高斯消元求行列式以及矩阵求逆,计算出A*,转置得到cof A。

对矩阵行展开求行列式的公式是:

当删去一条边时,只修改了A[u,u]与A[u,v],它们都在第u行,所以cof A的第u行不变。

我们可以按第u行展开,O(n)求解。多预处理一些东西,甚至可以O(1)求解。

代码:

 #include<bits/stdc++.h>
using namespace std;
const int mo=;
int n,m;
int ksm(int xx,int yy)
{
int zz=;
while(yy)
{
if(yy&)zz=(1ll*xx*zz)%mo;
yy>>=; xx=(1ll*xx*xx)%mo;
}
return zz;
}
int t[][];
struct matrix
{
int a[][];
void cheng(matrix &b) //矩阵乘法
{
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)
{
t[i][j]=;
for(int k=;k<=n;k++)t[i][j]=(1ll*a[i][k]*b.a[k][j]+t[i][j])%mo;
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)a[i][j]=t[i][j];
}
void hswap(int i,int j) //矩阵行交换
{
for(int k=;k<=*n;k++){ int t=a[i][k]; a[i][k]=a[j][k]; a[j][k]=t; }
}
void hadd(int i,int j,int l) //矩阵行之间加减
{
for(int k=;k<=*n;k++)a[j][k]=(1ll*l*a[i][k]+a[j][k])%mo;
}
void qiuni() //矩阵求逆
{
int flag=;
for(int i=;i<=n;i++)a[i][i+n]=;
for(int i=;i<=n;i++)
{
int j=i; while((j<=n)and(a[j][i]==))j++;
if(j>n){ flag=; break; }
if(i!=j)hswap(i,j);
for(int j=i+;j<=n;j++)if(a[j][i]!=)
{
int xx=(1ll*a[j][i]*ksm(a[i][i],mo-))%mo;
hadd(i,j,(-xx)%mo);
}
}
if(flag==){ for(int i=;i<=n;i++)for(int j=;j<=*n;j++)a[i][j]=; return; }
for(int i=n;i>=;i--)
{
int xx=ksm(a[i][i],mo-); hadd(i,i,(xx-)%mo);
for(int j=;j<i;j++)if(a[j][i]!=)hadd(i,j,(-a[j][i])%mo);
}
for(int i=;i<=n;i++)
for(int j=;j<=n;j++){ a[i][j]=a[i][j+n]; a[i][j+n]=; }
}
int det() //求矩阵行列式
{
int ans=;
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)t[i][j]=a[i][j];
for(int i=;i<=n;i++)
{
int j=i; while((j<=n)and(a[j][i]==))j++;
if(j>n)break;
if(i!=j)hswap(i,j),ans=-ans;
for(int j=i+;j<=n;j++)if(a[j][i]!=)
{
int xx=(1ll*a[j][i]*ksm(a[i][i],mo-))%mo;
hadd(i,j,(-xx)%mo);
}
}
for(int i=;i<=n;i++)ans=(1ll*ans*a[i][i])%mo;
for(int i=;i<=n;i++)for(int j=;j<=n;j++)a[i][j]=t[i][j];
return ans;
}
void zhuanzhi() //矩阵转置
{
for(int i=;i<=n;i++)
for(int j=;j<i;j++){ int t=a[i][j]; a[i][j]=a[j][i]; a[j][i]=t; }
}
} x,y;
int b[][],w[];
int ans,ans2,tot;
int main()
{
freopen("calc.in","r",stdin);
freopen("calc.out","w",stdout);
scanf("%d%d",&n,&m);
for(int i=;i<=m;i++)scanf("%d%d%d",&b[i][],&b[i][],&w[i]);
for(int i=;i<=m;i++)
if(b[i][]<n){ (x.a[b[i][]][b[i][]]+=)%=mo; if(b[i][]<n)(x.a[b[i][]][b[i][]]-=)%=mo; }
n--; int ans=x.det();
int ni=ksm(ans,mo-);
for(int i=;i<=n;i++)
for(int j=;j<=n;j++)y.a[i][j]=(1ll*x.a[i][j]*ni)%mo;
y.qiuni(); y.zhuanzhi();
for(int i=;i<=m;i++)
if(b[i][]<=n)
{
ans2=;
(x.a[b[i][]][b[i][]]-=)%=mo; if(b[i][]<=n)(x.a[b[i][]][b[i][]]+=)%=mo;
for(int j=;j<=n;j++)
ans2=(1ll*x.a[b[i][]][j]*y.a[b[i][]][j]+ans2)%mo;
tot=(1ll*(ans-ans2)*w[i]+tot)%mo;
(x.a[b[i][]][b[i][]]+=)%=mo; if(b[i][]<=n)(x.a[b[i][]][b[i][]]-=)%=mo;
}
tot=(tot+mo)%mo;
printf("%d\n",tot);
}

JZOJ5153:树形图求和的更多相关文章

  1. Java程序:从命令行接收多个数字,求和并输出结果

    一.设计思想:由于命令行接收的是字符串类型,因此应先将字符串类型转化为整型或其他字符型,然后利用for循环求和并输出结果 二.程序流程图: 三.源程序代码:   //王荣荣 2016/9/23     ...

  2. Java之递归求和的两张方法

    方法一: package com.smbea.demo; public class Student { private int sum = 0; /** * 递归求和 * @param num */ ...

  3. EXCEL中对1个单元格中多个数字求和

    如A1=3779.3759.3769.3781.3750,A2对A1中4个数字求和怎么求!请高手赐教! 方法一:在B1中输入公式=SUM(MID(A1,{1,6,11,16,21},4)*1) 方法二 ...

  4. codevs 1082 线段树区间求和

    codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...

  5. 从sum()求和引发的思考

    sum()求和是一个非常简单的函数,以前我的写法是这样,我想大部分和我一样刚开始学习JS的同学写出来的也会是这样. function sum() { var total=null; for(var i ...

  6. //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和

    //给定N个整数序列{A1,A2,A3...An},求函数f(i,j)=(k=i~j)Ak的求和 # include<stdio.h> void main() { ,sum1; ]={,- ...

  7. Ajax中get请求和post请求

    我们在使用Ajax向服务器发送数据时,可以采用Get方式请求服务器,也可以使用Post方式请求服务器,那么什么时候该采用Get方式,什么时候该采用Post方式呢? Get请求和Post请求的区别: 1 ...

  8. bzoj4349: 最小树形图

    最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 ...

  9. POJ 2823 Sliding Window 线段树区间求和问题

    题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...

随机推荐

  1. nodejs 进阶:图片裁剪

    demo 图片: 效果: var fs = require('fs'); var gm = require('gm'); gm("./不饿.jpg").crop(100,100,2 ...

  2. Comet Contest#11 F arewell(DAG计数+FWT子集卷积)

    传送门. 题解: 4月YY集训时做过DAG计数,和这个基本上是一样的,但是当时好像直接暴力子集卷积,不然我省选时不至于不会,这个就多了个边不选的概率和子集卷积. DAG计数是个套路来的,利用的是DAG ...

  3. phpMailer 手册

    phpMailer5.0.0属性: 英文地址:http://phpmailer.worxware.com/index.php?pg=properties 属性 (v5.0.0) 类型 默认 描述 $P ...

  4. Idea 导入项目不能运行

    1.项目结构里面配置sdk,配置output输出目录 2.配置语言等级 配置src源文件目录 配置目录里面添加application,添加main class

  5. Dubbo入门到精通学习笔记(四):持续集成管理平台之Maven私有库和本地库的安装与配置

    文章目录 介绍 Maven私有库和本地库的安装与配置 Nexus安装 Nexus 配置(登录后) 介绍 如果构建的Maven项目本地仓库没有对应的依赖包,那么就会去Nexus私服去下载, 那么如果Ne ...

  6. 3.1 开始使用 redux

    前面我们介绍了 flux 架构以及其开源实现 redux,在这一节中,我们将完整的介绍 redux: redux 介绍 redux 是什么 redux 概念 redux 三原则 redux Store ...

  7. 剑指offer——43数据流中的中位数

    题目描述 如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值.如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值.我们 ...

  8. 前端(二十三)—— Vue环境搭建

    目录 一.Vue环境搭建 一.Vue环境搭建 1.安装node 去官网下载node安装包 傻瓜式安装 万一安装后终端没有node环境,要进行node环境变量的配置(C:\Program Files\n ...

  9. Java 自动检测文本文件编码

    private String guessCharset(InputStream is) throws IOException { return new TikaEncodingDetector().g ...

  10. react map循环数据 死循环

    项目条件:react es6 antidesign 已在commonState中获取到list,但是在循环map填充DOM的时候陷入死循环. 原因:因为是子组件 ,在父组件请求数据的时候 有个时差过程 ...