码迷,mamicode.com
首页 > 其他好文 > 详细

【YbtOJ#893】带权的图

时间:2021-02-18 13:00:29      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:int   求值   class   printf   open   space   消元   mat   题目   

题目

题目链接:https://www.ybtoj.com.cn/contest/114/problem/2
技术图片
\(n\leq 100,m\leq 2000,a,b<P\leq 10^{18}\)

思路

上来就是一堆条件要你求值直接劝退。。。
根据条件三,可以得到对于任意一个环

\[\sum B(v_i,v_{i+1})C(v_i,v_{i+1})-A(v_i,v_{i+1})\equiv 0\pmod p \]

对于一条边 \((u,v)\),记 \(D(u,v)=\sum B(v_i,v_{i+1})C(v_i,v_{i+1})-A(v_i,v_{i+1})\),对于环上两点 \(x,y\),我们把环拆成 \(x\to y\)\(y\to x\) 的路径,那么

\[\sum_{x\to y}D(v_i,v_{i+1})+\sum_{y\to x}D(u_i,u_{i+1})\equiv 0\pmod p \]

再根据条件一

\[\sum_{x\to y}D(v_i,v_{i+1})\equiv\sum_{y\to x}D(u_{i+1},u_i) \pmod p \]

也就是任意两条 \(x\to y\) 的路径中,\(\sum D\) 都相等。
所以考虑做差分,记 \(g_x\) 表示 \(1\)\(x\)\(\sum D\),那么 \(D(x,y)=g_y-g_x\)
然后根据条件二可以对每一个点 \(x\) 列出一个方程

\[\sum_{(x,y)\in E}\frac{g_y-g_x+A(x,y)}{B(x,y)}\equiv 0\pmod p \]

高斯消元 \(O(n^3)\) 求出 \(g\),然后就知道 \(C\) 了。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;

const int N=110,M=2010;
int n,m,U[M],V[M];
ll MOD,a[N][N],b[N][N],f[N][N],g[N];
bool G[N][N];

ll fmul(ll x,ll y)
{
	ll z=(ld)x*y/MOD,res=x*y-z*MOD;
	return (res%MOD+MOD)%MOD;
}

ll fpow(ll x,ll k)
{
	ll ans=1;
	for (;k;k>>=1,x=fmul(x,x)%MOD)
		if (k&1) ans=fmul(ans,x)%MOD;
	return ans;
}

void gauss()
{
	for (int i=1;i<=n;i++)
	{
		for (int j=i;j<=n;j++)
			if (f[j][i])
			{
				for (int k=1;k<=n;k++)
					swap(f[i][k],f[j][k]);
				swap(g[i],g[j]);
				break;
			}
		for (int j=i+1;j<=n;j++)
			if (f[j][i])
			{
				ll base=fmul(f[i][i],fpow(f[j][i],MOD-2))%MOD;
				for (int k=1;k<=n;k++)
					f[j][k]=(fmul(f[j][k],base)-f[i][k])%MOD;
				g[j]=(fmul(g[j],base)-g[i])%MOD;
			}
	}
	for (int i=n;i>=1;i--)
	{
		ll sum=0;
		for (int j=i+1;j<=n;j++)
			sum=(sum+fmul(g[j],f[i][j]))%MOD;
		g[i]=fmul(g[i]-sum,fpow(f[i][i],MOD-2))%MOD;
	}
}

int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	scanf("%d%d",&n,&m);
	scanf("%lld",&MOD);
	for (int i=1,x,y;i<=m;i++)
	{
		scanf("%d%d",&U[i],&V[i]); x=U[i]; y=V[i];
		scanf("%lld%lld",&a[x][y],&b[x][y]);
		G[x][y]=G[y][x]=1; 
		a[y][x]=-a[x][y]; b[y][x]=b[x][y];
	}
	for (int i=1;i<=n;i++)
		for (int j=1;j<=n;j++)
			if (G[i][j])
			{
				ll inv=fpow(b[i][j],MOD-2);
				f[i][j]=inv; f[i][i]=(f[i][i]-inv)%MOD;
				g[i]=(g[i]-fmul(inv,a[i][j]))%MOD;
			}
	gauss();
	for (int i=1;i<=m;i++)
	{
		int u=U[i],v=V[i];
		printf("%lld\n",fmul(g[v]-g[u]+a[u][v],fpow(b[u][v],MOD-2)));
	}
	return 0;
}

【YbtOJ#893】带权的图

标签:int   求值   class   printf   open   space   消元   mat   题目   

原文地址:https://www.cnblogs.com/stoorz/p/14404014.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!