LOJ2100 TJOI2015 线性代数

考虑把柿子展开,发现会变成
∑ i = 1 n ∑ j = 1 n A i ∗ A j ∗ B i , j − ∑ i = 1 n A i ∗ C i \sum_{i=1}^n \sum_{j=1}^n A_i*A_j*B_{i,j}-\sum_{i=1}^n A_i*C_i i=1nj=1nAiAjBi,ji=1nAiCi
那么也就是说,如果 A i , A j A_i, A_j Ai,Aj同时为1,那么就会有 B i , j B_{i,j} Bi,j的收益,但是让单个 A i A_i Ai为1会有 C i C_i Ci的花费,然后跑一个收益-花费的网络流即可
每次先加上所有的收益,然后 S S S n ∗ n n*n nn个点连收益,剩下 n n n个点向 T T T连花费,然后跑网络流,减去此时的最小割即可

#include <bits/stdc++.h>

using namespace std;

using ll = long long;

int const N = 260000;
int const M = N * 10;
int const inf = 10000000;

struct ISAP {
	struct Edge {
		int y,f,next;
	}e[M];
	int last[N],ne;

	int d[N],cur[N],pre[N],num[N];
	int S,T,nv;

	void init(int _n) {
		S=_n+1; T=_n+2;
		nv=T+1;
		ne=0;
		memset(last,-1,sizeof(last));
	}

	void add(int x,int y,int f) {
		e[ne].y=y; e[ne].f=f; e[ne].next=last[x]; last[x]=ne; ne++;
	}
	void link(int x,int y,int f) {
		add(x,y,f);
		add(y,x,0);
	}

	void rev_bfs() {
		memset(num,0,sizeof(num));
		memset(d,-1,sizeof(d));
		d[T]=0;
		num[0]=1;
		queue<int> Q;
		while(!Q.empty()) Q.pop();
		Q.push(T);
		while(!Q.empty()) {
			int x=Q.front(); Q.pop();
			for(int i=last[x];~i;i=e[i].next) {
				int y=e[i].y;
				if(~d[y]) continue;
				d[y]=d[x]+1;
				num[d[y]]++;
				Q.push(y);
			}
		}
	}

	int solve() {
		memset(pre,0,sizeof(pre));
		memcpy(cur,last,sizeof(cur));
		rev_bfs();
		if(d[S]==-1) return 0; ///不联通
		int ret=0;
		int u=pre[S]=S,i;

		while(d[T]<nv) {
			if(u==T) {
				int f=inf;
				int neck;
				for(i=S;i!=T;i=e[cur[i]].y) {
					if(f>e[cur[i]].f) {
						f=e[cur[i]].f;
						neck=i;
					}
				}
				for(i=S;i!=T;i=e[cur[i]].y) {
					e[cur[i]].f-=f;
					e[cur[i]^1].f+=f;
				}
				ret+=f;
				u=neck;
			}
			for(i=cur[u];~i;i=e[i].next) if(d[e[i].y]+1==d[u] && e[i].f) break;
			if(~i) {
				cur[u]=i;
				pre[e[i].y]=u;
				u=e[i].y;
			} else {
				if(0== (--num[d[u]])) break;
				int mind=nv;
				for(i=last[u];~i;i=e[i].next) {
					if(e[i].f && mind>d[e[i].y]) {
						cur[u]=i;
						mind=d[e[i].y];
					}
				}
				d[u]=mind+1;
				num[d[u]]++;
				u=pre[u];
			}
		}
		return ret;
	}
} isap;

int b[501][501];
int c[501];
int n;

int main() {
    ios::sync_with_stdio(0);
    cin >> n;
    isap.init(n * n + n);
    ll ans = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= n; ++j) {
            cin >> b[i][j];
            ans += b[i][j];
            int now = (i - 1) * n + j;
            isap.link(isap.S, now, b[i][j]);
            isap.link(now, n * n + i, inf);
            isap.link(now, n * n + j, inf);
        }
    for (int i = 1; i <= n; ++i) {
        cin >> c[i];
        isap.link(n * n + i, isap.T, c[i]);
    }
    cout << ans - isap.solve() << '\n';
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值