ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【YbtOJ#593】木棍问题

2021-02-15 17:32:46  阅读:196  来源: 互联网

标签:593 int YbtOJ ll ans long fmul 木棍 MOD


题目

题目链接:https://www.ybtoj.com.cn/contest/114/problem/3



\(n,m\leq 40\)。

思路

黑白染色,考虑如下建图

把 \(B\) 看作 \(A+(B-A)\),那么一个点有 \(x\) 流量就需要 \(\binom{2}{x}A\) 贡献。对于 \(x\in[0,4]\),做差分之后分别为 \(0,A,2A,3A\),恰好严格不减,这样如果选择 \(x\) 的流量就一定会走最小的 \(x\) 条边,总费用加起来恰好是 \(\binom{2}{x}A\)。
考虑加上直线的贡献 \(B-A\)。那么就把每个点再拆出两个点来,分别表示行和列,如果一行或一列只选择一个,就不会产生多于贡献;选择两个就会产生 \(B-A\) 的贡献,所以连两条边流量为 \(1\),费用分别为 \(0\) 和 \(B-A\) 即可。
由于费用流每次只增广一条路径,而不难发现我们的连边每次增广都只会增加 \(1\) 的流量,所以每次 addflow 之后输出即可。
时间复杂度 \(O(nm^2)\)。

代码

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

标签:593,int,YbtOJ,ll,ans,long,fmul,木棍,MOD
来源: https://www.cnblogs.com/stoorz/p/14404061.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有