• 【YbtOJ#593】木棍问题


    题目

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



    (n,mleq 40)

    思路

    黑白染色,考虑如下建图

    (B) 看作 (A+(B-A)),那么一个点有 (x) 流量就需要 (inom{2}{x}A) 贡献。对于 (xin[0,4]),做差分之后分别为 (0,A,2A,3A),恰好严格不减,这样如果选择 (x) 的流量就一定会走最小的 (x) 条边,总费用加起来恰好是 (inom{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
    ",fmul(g[v]-g[u]+a[u][v],fpow(b[u][v],MOD-2)));
    	}
    	return 0;
    }
    
  • 相关阅读:
    linux之参数实用讲解
    Linux脚本中调用SQL,RMAN脚本
    shell for参数
    Linux Shell参数替换
    Python OOP(1)
    Python 不可变对象
    Python set
    Python tuple
    Python list,tuple,dict and set
    Python 可变长度函数参数
  • 原文地址:https://www.cnblogs.com/stoorz/p/14404061.html
Copyright © 2020-2023  润新知