标签:turn 复杂 cdn 题目 oid 修改 表示 code stdin
LINK:树形图求和
很妙的题目 因为之前没有了解过 有向图的矩阵树 所以自然GG了.
这里先给出矩阵树定理的三种形式 防止以后再考。
第一种 无向图的矩阵树 总所周知.
第二种 有向图的内向树 所谓内向树就是所有的点都指向一个点的有向树.
邻接矩阵矩阵 \(a_{i,j}\)表示i到j的路径条数 度数矩阵 \(a_{i,j}\)表示i的出度 拉普拉斯矩阵还是为度数矩阵-邻接矩阵 最后需要把根的那行那列去掉.
第三种 有向图的外向树 所谓外向树就是由某个点发出所有点都指向叶子节点.
邻接矩阵矩阵 \(a_{i,j}\)表示i到j的路径条数 度数矩阵 \(a_{i,j}\)表示i的入度 基尔霍夫矩阵还是为度数矩阵-邻接矩阵 最后需要把根的那行那列去掉.
对于20分 爆搜.复杂度C(30,9).
对于60分 如果把每条边看成多项式 不过这道题最后生成的多项式次数过大 插值是不能插出来的。
所以考虑每一条边的贡献 想办法求出某条边的方案数 容易想到总方案-不包含的很好算.
GAUSS消元求行列式 复杂度mn^3logn.
对于100分 有一个定理:当某一行或者某一列改变可以快速求出之后DET.
考虑某一行被修改成了 c1,c2,c3...
那么有 每一列有方程组\(\sum{a_{i,j}\cdot x_i}=c_j\)
求出\(x_i\)之后 将之前的DET乘上\(x_i\)即可得到当前矩阵的行列式.
不过这里\(c_j\)是动态变化的 考虑变成\(x_i=\sum_jb_j\cdot c_j\)的形式就可以快速求出\(x_i\)了。
这里列出方程后可以对右边列一个单位矩阵来高斯消元 这样就可以求出刚才那个形式了(也是矩阵求逆的过程.
最后求答案可以每次都扫一遍 当然还有更快的做法:简单推一下就知道了(见code.
值得注意的是 GAUSS的时候注意别漏了ll.
(感觉有点不太对劲 奈何实力有限 止步于此~
const int MAXN=310,G=3;
int n,m;
int a[MAXN][MAXN],f[MAXN][MAXN],I[MAXN][MAXN];
struct wy
{
int x,y,z;
}t[100010];
inline void add(int x,int y)
{
--a[x][y];++a[x][x];
}
inline int ksm(int b,int p)
{
int cnt=1;
while(p)
{
if(p&1)cnt=(ll)cnt*b%mod;
b=(ll)b*b%mod;p=p>>1;
}
return cnt;
}
inline int DET(int n)
{
int ans=1;
rep(1,n,i)
{
rep(i+1,n,j)
{
while(a[j][i])
{
int d=a[i][i]/a[j][i];
rep(i,n,k)a[i][k]=(a[i][k]-(ll)d*a[j][k])%mod;
rep(1,n,k)swap(a[i][k],a[j][k]);
ans=-ans;
}
}
if(!a[i][i]){return 0;}
ans=(ll)ans*a[i][i]%mod;
}
return (ans+mod)%mod;
}
inline void GAUSS(int n)
{
rep(1,n,i)
{
int p=i;
rep(i,n,j)if(f[j][i])p=j;
if(p!=i)rep(1,n,j)swap(f[i][j],f[p][j]),swap(I[i][j],I[p][j]);
int ww=ksm(f[i][i],mod-2);
rep(1,n,j)
{
if(i==j)continue;
int d=(ll)f[j][i]*ww%mod;
rep(1,n,k)
{
f[j][k]=(f[j][k]-(ll)d*f[i][k]%mod+mod)%mod;
I[j][k]=(I[j][k]-(ll)d*I[i][k]%mod+mod)%mod;
}
}
rep(1,n,j)f[i][j]=(ll)f[i][j]*ww%mod,I[i][j]=(ll)I[i][j]*ww%mod;
}
}
int main()
{
freopen("calc.in","r",stdin);
freopen("calc.out","w",stdout);
get(n);get(m);
rep(1,m,i)
{
int get(x),get(y),get(z);
t[i]=(wy){x,y,z};
add(x,y);
}
rep(1,n,i)
{
I[i][i]=1;
rep(1,n,j)f[i][j]=a[j][i];
}
GAUSS(n);//解方程.
int ans=DET(n-1);
int sum=0;
rep(1,m,i)
{
int x=t[i].x,y=t[i].y;
if(x<n)
{
int ww=(I[x][x]-I[x][y]+mod)%mod;
sum=(sum+(ll)ans*ww%mod*t[i].z)%mod;
}
}
put(sum);return 0;
}
5.29 省选模拟赛 树形图求和 有向图矩阵树定理 高斯消元 行列式
标签:turn 复杂 cdn 题目 oid 修改 表示 code stdin
原文地址:https://www.cnblogs.com/chdy/p/12989268.html