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

1|0正题

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


1|1题目大意

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

Ax,y=Ay,x , Bx,y=By,x , Cx,y=Cy,x

x>yCx,y=0

且对于每个环[v1,v2...vn](v1=vn)

i=1n1Cvi,vi+1×Bvi,vi+1=i=1n1Avi,vi+1

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

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

n[1,100],m[1,2000],P[1,1018]Pri


1|2解题思路

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

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

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

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

Dx,y=Bx,y×Cx,yAx,y,那么第一个条件就表示成了每个环D的和为0

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

path(y,x)+Dx,y=0,path(x,y)=path(y,x),Dx,y=path(x,y)

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

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

那么我们可以设fx=path(1,x),那么Dx,y=fyfx

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

x>yfyfx+Ax,yBx,y=0

然后高斯消元即可,时间复杂度O(n3)

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


1|3code

#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; }

__EOF__

本文作者QuantAsk
本文链接https://www.cnblogs.com/QuantAsk/p/14403857.html
关于博主:退役OIer,GD划水选手
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   QuantAsk  阅读(33)  评论(0编辑  收藏  举报
编辑推荐:
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 张高兴的大模型开发实战:(一)使用 Selenium 进行网页爬虫
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构
点击右上角即可分享
微信分享提示