JZOJ5153:树形图求和
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:树形图求和的更多相关文章
- Java程序:从命令行接收多个数字,求和并输出结果
一.设计思想:由于命令行接收的是字符串类型,因此应先将字符串类型转化为整型或其他字符型,然后利用for循环求和并输出结果 二.程序流程图: 三.源程序代码: //王荣荣 2016/9/23 ...
- Java之递归求和的两张方法
方法一: package com.smbea.demo; public class Student { private int sum = 0; /** * 递归求和 * @param num */ ...
- EXCEL中对1个单元格中多个数字求和
如A1=3779.3759.3769.3781.3750,A2对A1中4个数字求和怎么求!请高手赐教! 方法一:在B1中输入公式=SUM(MID(A1,{1,6,11,16,21},4)*1) 方法二 ...
- codevs 1082 线段树区间求和
codevs 1082 线段树练习3 链接:http://codevs.cn/problem/1082/ sumv是维护求和的线段树,addv是标记这歌节点所在区间还需要加上的值. 我的线段树写法在运 ...
- 从sum()求和引发的思考
sum()求和是一个非常简单的函数,以前我的写法是这样,我想大部分和我一样刚开始学习JS的同学写出来的也会是这样. function sum() { var total=null; for(var i ...
- //给定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; ]={,- ...
- Ajax中get请求和post请求
我们在使用Ajax向服务器发送数据时,可以采用Get方式请求服务器,也可以使用Post方式请求服务器,那么什么时候该采用Get方式,什么时候该采用Post方式呢? Get请求和Post请求的区别: 1 ...
- bzoj4349: 最小树形图
最小树形图模板题…… 这种\(O(nm)\)的东西真的能考到么…… #include <bits/stdc++.h> #define N 60 #define INF 1000000000 ...
- POJ 2823 Sliding Window 线段树区间求和问题
题目链接 线段树区间求和问题,维护一个最大值一个最小值即可,线段树要用C++交才能过. 注意这道题不是求三个数的最大值最小值,是求k个的. 本题数据量较大,不能用N建树,用n建树. 还有一种做法是单调 ...
随机推荐
- 笔记59 Spring+Hibernate整合(二)
一.项目结构 二.创建表 数据库中只有一张表,stock,三个字段:stock_id.stock_code和stock_name. CREATE TABLE `stock` ( `STOCK_ID` ...
- ES5的 forEach, map 方法的实现
如果浏览器不支持forEach,map方法, 要我们自己封装一个, 该怎么操作呢? 1. forEach Array.prototype.forEach = function(fn) { if (th ...
- nodejs 静态资源文件与登陆交互
server2.js var express=require('express'); var expressStatic=require('express-static'); var server=e ...
- 36.两个链表的第一个公共结点(python)
题目描述 输入两个链表,找出它们的第一个公共结点. class Solution: def FindFirstCommonNode(self, pHead1, pHead2): # write cod ...
- 什么是平衡树B-Tree?【转】
转载自:https://www.cnblogs.com/dongguacai/p/7239599.html#commentform B-Tree就是我们常说的B树,一定不要读成B减树,否则就很丢人了. ...
- 利用Python批量重命名一系列文件名杂乱的文件
假设目录下面有这样一系列命令杂乱的文件: OPENFOAM -TRAINING- PART- #1.pdf OPENFOAM - TRAINING- PART- #2.pdf OPENFOAM- TR ...
- java基础方法笔记
Java环境 1.编译 javac HelloWorld.java 2.运行 java HelloWorld 3.执行class文件 java -classpath C:\java\myclasses ...
- Java-Class-FC:java.lang.StringBuilder
ylbtech-Java-Class-FC:java.lang.StringBuilder 1.返回顶部 2.返回顶部 1. @Override public String toString() ...
- $.ajax(),传参要用data
$("#modal").find(".btn-primary").unbind("click").click(function(){ var ...
- 剑指offer——69队列的最大值
题目: 队列的最大值.请定义一个队列并实现函数max得到队列里的最大值,要求函数max.push_back和pop_front的时间复杂度都是O(1). 题解: 使用队列,操持队列的排序为从大到小的顺 ...