YbtOJ#893-带权的图【高斯消元,结论】
正題
題目鏈接:https://www.ybtoj.com.cn/problem/893
題目大意
給出一張nnn個點mmm條邊的無向聯通圖,每條邊正反向各有A,B,CA,B,CA,B,C三種邊權。
保證滿足
Ax,y=?Ay,x,Bx,y=By,x,Cx,y=?Cy,xA_{x,y}=-A_{y,x}\ ,\ B_{x,y}=B_{y,x}\ ,\ C_{x,y}=-C_{y,x}Ax,y?=?Ay,x??,?Bx,y?=By,x??,?Cx,y?=?Cy,x?
∑x?>yCx,y=0\sum_{x->y}C_{x,y}=0x?>y∑?Cx,y?=0
且對于每個環[v1,v2...vn](v1=vn)[v_1,v_2...v_n](v_1=v_n)[v1?,v2?...vn?](v1?=vn?)
∑i=1n?1Cvi,vi+1×Bvi,vi+1=∑i=1n?1Avi,vi+1\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}}i=1∑n?1?Cvi?,vi+1??×Bvi?,vi+1??=i=1∑n?1?Avi?,vi+1??
現在給你A,BA,BA,B邊權,求CCC邊權。
數據保證解唯一,所有限制都在模PPP意義下
n∈[1,100],m∈[1,2000],P∈[1,1018]∪Prin\in[1,100],m\in[1,2000],P\in[1,10^{18}]\cup Prin∈[1,100],m∈[1,2000],P∈[1,1018]∪Pri
解題思路
最后一個環的限制很麻煩,因為環很多。
先考慮原圖的任意一顆生成樹TTT上,對于任意一條非樹邊(u,v)(u,v)(u,v)可以表示一個u?>v?>uu->v->uu?>v?>u的環。并且因為反過來走邊權為負,所以你可以通過用一些小環相互抵消出一個大環。
結論就是所有的環都可以被一些用非樹邊表示的環相互抵消表示。所以我們就可以將環的數量減少到O(m)O(m)O(m)級別了。
暴力消元O(m3)O(m^3)O(m3)顯然無法通過本題,我們還需要優化。
設Dx,y=Bx,y×Cx,y?Ax,yD_{x,y}=B_{x,y}\times C_{x,y}-A_{x,y}Dx,y?=Bx,y?×Cx,y??Ax,y?,那么第一個條件就表示成了每個環DDD的和為000。
并且還能發現一個性質,對于一個非樹邊表示的環(x,y)(x,y)(x,y),
path(y,x)+Dx,y=0,path(x,y)=?path(y,x),?Dx,y=path(x,y)path(y,x)+D_{x,y}=0,path(x,y)=-path(y,x),\Rightarrow D_{x,y}=path(x,y)path(y,x)+Dx,y?=0,path(x,y)=?path(y,x),?Dx,y?=path(x,y)
(其中path(x,y)path(x,y)path(x,y)表示樹上路徑x,yx,yx,y的DDD值和)
所以可以證明從xxx走到yyy的所有路徑權值相同
那么我們可以設fx=path(1,x)f_x=path(1,x)fx?=path(1,x),那么Dx,y=fy?fxD_{x,y}=f_y-f_xDx,y?=fy??fx?。
這樣對于每個點就可以根據CCC的限制列出一個方程
∑x?>yfy?fx+Ax,yBx,y=0\sum_{x->y}\frac{f_y-f_x+A_{x,y}}{B_{x,y}}=0x?>y∑?Bx,y?fy??fx?+Ax,y??=0
然后高斯消元即可,時間復雜度O(n3)O(n^3)O(n3)
注意模數比較大,要寫龜速乘
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; }總結
以上是生活随笔為你收集整理的YbtOJ#893-带权的图【高斯消元,结论】的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: YbtOJ#631-次短路径【左偏树,最
- 下一篇: YbtOJ#593-木棍问题【费用流】