zoukankan      html  css  js  c++  java
  • 5.29 省选模拟赛 树形图求和 有向图矩阵树定理 高斯消元 行列式

    LINK:树形图求和

    avatar
    avatar

    很妙的题目 因为之前没有了解过 有向图的矩阵树 所以自然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_jcdot 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;
    }
    
  • 相关阅读:
    第一模块第一章 review
    python练习题:三级菜单
    python list()总结
    python中index()、find()方法
    python中join()函数、list()函数补充的用法
    python中关键字的总结
    python中for循环的用法
    python中range()、list()函数的用法
    python中pop()函数的用法
    python中split()、os.path.split()函数用法
  • 原文地址:https://www.cnblogs.com/chdy/p/12989268.html
Copyright © 2011-2022 走看看