• YbtOJ#893带权的图【高斯消元,结论】


    正题

    题目链接:https://www.ybtoj.com.cn/problem/893


    题目大意

    给出一张\(n\)个点\(m\)条边的无向联通图,每条边正反向各有\(A,B,C\)三种边权。
    保证满足

    \[A_{x,y}=-A_{y,x}\ ,\ B_{x,y}=B_{y,x}\ ,\ C_{x,y}=-C_{y,x} \]

    \[\sum_{x->y}C_{x,y}=0 \]

    且对于每个环\([v_1,v_2...v_n](v_1=v_n)\)

    \[\sum_{i=1}^{n-1}C_{v_i,v_{i+1}}\times B_{v_i,v_{i+1}}=\sum_{i=1}^{n-1}A_{v_i,v_{i+1}} \]

    现在给你\(A,B\)边权,求\(C\)边权。

    数据保证解唯一,所有限制都在模\(P\)意义下

    \(n\in[1,100],m\in[1,2000],P\in[1,10^{18}]\cup Pri\)


    解题思路

    最后一个环的限制很麻烦,因为环很多。

    先考虑原图的任意一颗生成树\(T\)上,对于任意一条非树边\((u,v)\)可以表示一个\(u->v->u\)的环。并且因为反过来走边权为负,所以你可以通过用一些小环相互抵消出一个大环。

    结论就是所有的环都可以被一些用非树边表示的环相互抵消表示。所以我们就可以将环的数量减少到\(O(m)\)级别了。

    暴力消元\(O(m^3)\)显然无法通过本题,我们还需要优化。

    \(D_{x,y}=B_{x,y}\times C_{x,y}-A_{x,y}\),那么第一个条件就表示成了每个环\(D\)的和为\(0\)

    并且还能发现一个性质,对于一个非树边表示的环\((x,y)\)

    \[path(y,x)+D_{x,y}=0,path(x,y)=-path(y,x),\Rightarrow D_{x,y}=path(x,y) \]

    (其中\(path(x,y)\)表示树上路径\(x,y\)\(D\)值和)

    所以可以证明从\(x\)走到\(y\)的所有路径权值相同

    那么我们可以设\(f_x=path(1,x)\),那么\(D_{x,y}=f_y-f_x\)

    这样对于每个点就可以根据\(C\)的限制列出一个方程

    \[\sum_{x->y}\frac{f_y-f_x+A_{x,y}}{B_{x,y}}=0 \]

    然后高斯消元即可,时间复杂度\(O(n^3)\)

    注意模数比较大,要写龟速乘


    code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    const ll N=110;
    struct node{
    	ll x,y,a,b;
    }e[N*20];
    ll n,m,P,f[N];
    ll mul(ll a,ll b){
    	a%=P;b%=P;
    	ll tmp=(long double)a*b/P;
    	long double ans=a*b-tmp*P;
    	if(ans>=P)ans-=P;
    	else if(ans<0)ans+=P;
    	return ans;
    }
    ll power(ll x,ll b){
    	ll ans=1;
    	while(b){
    		if(b&1)ans=mul(ans,x);
    		x=mul(x,x);b>>=1; 
    	}
    	return ans;
    }
    namespace G{
    	ll a[N][N],b[N];
    	void solve(ll *f){
    		for(ll i=1;i<=n;i++){
    			ll p=i;
    			for(ll j=i;j<=n;j++)
    				if(a[j][i]){p=j;break;}
    			swap(a[i],a[p]);swap(b[i],b[p]);
    			ll inv=power(a[i][i],P-2);b[i]=mul(b[i],inv);
    			for(ll j=i;j<=n;j++)a[i][j]=mul(a[i][j],inv);
    			for(ll j=i+1;j<=n;j++){
    				ll rate=P-a[j][i];
    				for(ll k=i;k<=n;k++)
    					a[j][k]=(a[j][k]+mul(rate,a[i][k]))%P;
    				b[j]=(b[j]+mul(rate,b[i]))%P;
    			}
    		}
    		for(ll i=n;i>=1;i--){
    			for(ll j=i+1;j<=n;j++)
    				(b[i]+=P-mul(b[j],a[i][j]))%=P;
    			f[i]=b[i];
    		}
    		return;
    	}
    }
    signed main()
    {
    	freopen("graph.in","r",stdin);
    	freopen("graph.out","w",stdout);
    	scanf("%lld%lld%lld",&n,&m,&P);
    	for(ll i=1;i<=m;i++)
    		scanf("%lld%lld%lld%lld",&e[i].x,&e[i].y,&e[i].a,&e[i].b);
    	for(ll i=1;i<=m;i++){
    		ll x=e[i].x,y=e[i].y,a=e[i].a,b=e[i].b;b=power(b,P-2);
    		(G::a[x][y]+=b)%=P;(G::a[x][x]+=P-b)%=P;(G::b[x]+=P-mul(a,b))%=P;
    		swap(x,y);a=P-a;
    		(G::a[x][y]+=b)%=P;(G::a[x][x]+=P-b)%=P;(G::b[x]+=P-mul(a,b))%=P;
    	}
    	for(ll i=1;i<=n;i++)G::a[1][i]=0;
    	G::a[1][1]=1;G::b[1]=0;G::solve(f);
    	for(ll i=1;i<=m;i++){
    		ll x=e[i].x,y=e[i].y,a=e[i].a,b=e[i].b;b=power(b,P-2);
    		printf("%lld\n",mul((f[y]-f[x]+a+P)%P,b));
    	}
    	return 0;
    }
    
  • 相关阅读:
    用SQL实现的一个自动排课机制
    如何读懂复杂的C声明
    Mingw32配置
    test
    HttpSession API
    java程序逻辑控制
    方法的定义及使用
    memcached 安装及集成(转)
    cookie和session的的区别以及使用示例?
    构造方法和普通方法的区别?
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/14403857.html
Copyright © 2020-2023  润新知