题目链接:https://www.ybtoj.com.cn/problem/893
给出一张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)
n−1∑i=1Cvi,vi+1×Bvi,vi+1=n−1∑i=1Avi,vi+1
现在给你A,B边权,求C边权。
数据保证解唯一,所有限制都在模P意义下
n∈[1,100],m∈[1,2000],P∈[1,1018]∪Pri
最后一个环的限制很麻烦,因为环很多。
先考虑原图的任意一颗生成树T上,对于任意一条非树边(u,v)可以表示一个u−>v−>u的环。并且因为反过来走边权为负,所以你可以通过用一些小环相互抵消出一个大环。
结论就是所有的环都可以被一些用非树边表示的环相互抵消表示。所以我们就可以将环的数量减少到O(m)级别了。
暴力消元O(m3)显然无法通过本题,我们还需要优化。
设Dx,y=Bx,y×Cx,y−Ax,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,y的D值和)
所以可以证明从x走到y的所有路径权值相同
那么我们可以设fx=path(1,x),那么Dx,y=fy−fx。
这样对于每个点就可以根据C的限制列出一个方程
∑x−>yfy−fx+Ax,yBx,y=0
然后高斯消元即可,时间复杂度O(n3)
注意模数比较大,要写龟速乘
#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__
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .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语句:使用策略模式优化代码结构