[TJOI 2015] 线性代数

题目传送-Luogu3973

题意:

给定一个\(n×n\)的矩阵\(B\)和一个\(1×n\)的矩阵\(C\),求一个\(1×n\)\(01\)矩阵\(A\)。使得\(D=(A×B-C)×A^{\sf T}\)最大,其中\(A^{\sf T}\)\(A\)的转置。输出\(D\)
\(n \le 500,1 \le Allelement \le 1000\)

题解:

emmm这是道网络流..二十多万条边跑网络流也是有信仰的了
脑补一下我们可以发现以下性质:
只有当\(a_i=1\)\(a_j=1\)时,\(B_{i,j}\)才能被算贡献
也就意味着必须要选上\(c_i\)\(c_j\)的代价才能有\(B_{i,j}\)的贡献
这东西就和这题等价啦link

过程:

我:500*500=25000

代码:

const int N=510,M=250010;
int n,m;
int p[N];
struct PEO {
	int a,b,v;
	inline void in() {
		read(a); read(b); read(v);
	}
}a[M];
namespace FLOW {
	const int ALL=N+M,EDGE=(N+M*3)<<1;
	int S,T;
	int head[ALL],nxt[EDGE],to[EDGE],cap[EDGE],lst=1;
	inline void adde(int x,int y,int c) {
		nxt[++lst]=head[x]; to[lst]=y; cap[lst]=c; head[x]=lst;
	}
	inline void con(int x,int y,int c) {
		adde(x,y,c); adde(y,x,0);
	}
	int stp[ALL];
	inline bool bfs(int S) {
		queue<int> que; mem(stp,63);
		que.push(S); stp[S]=0; 
		while(!que.empty()) {
			int u=que.front(); que.pop();
			for(int i=head[u];i;i=nxt[i]) {
				int v=to[i];
				if(cap[i] && stp[v]>stp[u]+1) {
					stp[v]=stp[u]+1;
					que.push(v);
				}
			}
		}
		return stp[T]!=stp[0];
	}
	int cur[ALL];
	inline int dfs(int u,int f) {
		if(!f || u==T) return f;
		for(int &i=cur[u];i;i=nxt[i]) {
			int v=to[i];
			if(stp[v]==stp[u]+1 && cap[i]) {
				int flow=dfs(v,min(f,cap[i]));
				if(flow) {
					cap[i]-=flow; cap[i^1]+=flow;
					return flow;
				}
			}
		}
		return 0;
	}
	inline int Dinic() {
		int Flow=0,add=0;
		while(bfs(S)) {

			memcpy(cur,head,sizeof(head));
			do {add=dfs(S,INF); Flow+=add;} while(add);
		}
		return Flow;
	}
	inline void Construct() {
		S=n+m+1; T=S+1;
		for(int i=1;i<=n;i++) {
			con(S,i,p[i]);
		}
		for(int i=1;i<=m;i++) {
			con(a[i].a,i+n,INF);
			con(a[i].b,i+n,INF);
			con(i+n,T,a[i].v);
		}
	}
	inline int main() {
		Construct();
		// printf("%lld %lld %lld %lld\n",S,T,lst,EDGE);
		return Dinic();
	}
}
int sum=0;
signed main() {
	read(n); m=n*n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++) {
			int p=(i-1)*n+j;
			a[p].a=i; a[p].b=j; read(a[p].v);
			sum+=a[p].v;
		}
	for(int i=1;i<=n;i++) read(p[i]);
	int ans=FLOW::main();
	printf("%d\n",sum-ans);
	return 0;
}

用时:5min(用模板)

posted @ 2018-08-29 20:37  functionendless  阅读(121)  评论(0编辑  收藏  举报