首页 > 其他分享 >AtCoder Beginner Contest 258 G Grid Card Game

AtCoder Beginner Contest 258 G Grid Card Game

时间:2023-06-04 22:11:32浏览次数:57  
标签:AtCoder Beginner Contest int ll flow add edges sum

洛谷传送门

AtCoder 传送门

记 \(b_i = \sum\limits_{j = 1}^m a_{i, j}, c_j = \sum\limits_{i = 1}^n a_{i, j}\)。

首先考虑这样一个事情,就是对于 \(b_i \le 0\) 的行有没有可能被选。如果选了它:

  • 如果没有选任何列,选这一行肯定不优;
  • 如果选了若干列,根据题目的要求,这若干列与这一行重叠的部分只可能是非负数。考虑看成是先选列再选行,那选这一行必然会造成负贡献,雪上加霜。

所以我们得到只选 \(b_i > 0\) 的行一定不劣。类似地,只选 \(c_j > 0\) 的列也一定不劣。

这种行列网格的题,可以考虑转化成二分图一类的问题。考虑直接硬冲一个最大费用最大流。下面设 \((u, v, x, y)\) 表示一条 \(u \to v\),容量 \(x\),费用 \(y\) 的边。行作为左部点,列作为右部点。

  • 对于 \(S\) 到左部点的边,若 \(b_i \le 0\) 直接不管,否则我们希望有流量就产生 \(b_i\) 的贡献,而不管流量多少。因此连边 \((S, i, 1, b_i), (S, i, +\infty, 0)\)。
  • 对于一个匹配,可以看成是这一行跟这一列都选。那么重叠的部分要减掉,即连边 \((i, j, 1, -a_{i, j})\)。
  • 对于右部点到 \(T\) 的边,类似地,连边 \((j, T, 1, c_j), (j, T, +\infty, 0)\)。

最后答案就是最大费用。

但是理论复杂度是 \(O(n^5)\) 的,实际也会 T 得很惨

类似 ABC214H 地考虑,不妨换种思路,计算最少损失(初始的答案是 \(\sum\limits_{i = 1}^n b_i + \sum\limits_{j = 1}^m c_j\))。考虑转化成最小割,这样建图(用 \((u, v, x)\) 表示一条 \(u \to v\),容量为 \(x\) 的边):

  • 对于 \(b_i > 0\) 的行,连边 \((S, i, b_i)\);
  • 对于 \(c_j > 0\) 的列,连边 \((j, T, c_j)\);
  • 对于 \(a_{i, j} \ge 0\),连边 \((i, j, a_{i, j})\);
  • 对于 \(a_{i, j} < 0\),连边 \((i, j, +\infty)\)。

这样保证了对于任意 \(S \to i \to j \to T\) 的路径:

  • 要么割掉 \(S \to i\) 或 \(j \to T\) 的边,表示它们不同时被选;
  • 要么割掉 \(i \to j\) 的边,表示它们同时被选,但是因为有重叠,所以产生了 \(-a_{i, j}\) 的负贡献;
  • 如果 \(a_{i, j} < 0\),那么也能保证 \(i, j\) 不同时被选,因为 \(i \to j\) 的边权是 \(+\infty\),表示它不能被割,只能割 \(S \to i\) 或 \(j \to T\) 的边。

最后答案就是 \(\sum\limits_{i = 1}^n b_i + \sum\limits_{j = 1}^m c_j - \text{mincut} = \sum\limits_{i = 1}^n b_i + \sum\limits_{j = 1}^m c_j - \text{maxflow}\)。

因为这是二分图,所以时间复杂度是 \(O(n^{2.5})\)。

code
// Problem: G - Grid Card Game
// Contest: AtCoder - AtCoder Beginner Contest 259
// URL: https://atcoder.jp/contests/abc259/tasks/abc259_g
// Memory Limit: 1024 MB
// Time Limit: 2000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

#include <bits/stdc++.h>
#define pb emplace_back
#define fst first
#define scd second
#define mems(a, x) memset((a), (x), sizeof(a))

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ldb;
typedef pair<ll, ll> pii;

const int maxn = 110;
const int maxm = 1000100;
const ll inf = 0x3f3f3f3f3f3f3f3fLL;

ll n, m, a[maxn][maxn], head[maxm], len = 1, ntot, S, T, b[maxn], c[maxn], id[maxn][2];
struct edge {
	ll to, next, cap, flow;
} edges[maxm];

inline void add_edge(ll u, ll v, ll c, ll f) {
	edges[++len].to = v;
	edges[len].next = head[u];
	edges[len].cap = c;
	edges[len].flow = f;
	head[u] = len;
}

struct Dinic {
	ll d[maxm], cur[maxm];
	bool vis[maxm];
	
	inline void add(ll u, ll v, ll c) {
		add_edge(u, v, c, 0);
		add_edge(v, u, 0, 0);
	}
	
	bool bfs() {
		for (int i = 1; i <= ntot; ++i) {
			d[i] = -1;
			vis[i] = 0;
		}
		queue<int> q;
		q.push(S);
		d[S] = 0;
		vis[S] = 1;
		while (q.size()) {
			int u = q.front();
			q.pop();
			for (int i = head[u]; i; i = edges[i].next) {
				edge &e = edges[i];
				if (e.cap > e.flow && !vis[e.to]) {
					vis[e.to] = 1;
					d[e.to] = d[u] + 1;
					q.push(e.to);
				}
			}
		}
		return vis[T];
	}
	
	ll dfs(ll u, ll a) {
		if (u == T || !a) {
			return a;
		}
		ll flow = 0, f;
		for (ll &i = cur[u]; i; i = edges[i].next) {
			edge &e = edges[i];
			if (d[e.to] == d[u] + 1 && (f = dfs(e.to, min(a, e.cap - e.flow))) > 0) {
				e.flow += f;
				edges[i ^ 1].flow -= f;
				flow += f;
				a -= f;
				if (!a) {
					break;
				}
			}
		}
		return flow;
	}
	
	ll solve() {
		ll flow = 0;
		while (bfs()) {
			for (int i = 1; i <= ntot; ++i) {
				cur[i] = head[i];
			}
			ll t = dfs(S, inf);
			flow += t;
		}
		return flow;
	}
} solver;

void solve() {
	scanf("%lld%lld", &n, &m);
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			scanf("%lld", &a[i][j]);
			b[i] += a[i][j];
			c[j] += a[i][j];
		}
	}
	ll s = 0;
	for (int i = 1; i <= n; ++i) {
		if (b[i] > 0) {
			s += b[i];
		}
	}
	for (int i = 1; i <= m; ++i) {
		if (c[i] > 0) {
			s += c[i];
		}
	}
	S = ++ntot;
	T = ++ntot;
	for (int i = 1; i <= n; ++i) {
		id[i][0] = ++ntot;
	}
	for (int i = 1; i <= m; ++i) {
		id[i][1] = ++ntot;
	}
	for (int i = 1; i <= n; ++i) {
		if (b[i] > 0) {
			solver.add(S, id[i][0], b[i]);
		}
	}
	for (int i = 1; i <= m; ++i) {
		if (c[i] > 0) {
			solver.add(id[i][1], T, c[i]);
		}
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			if (a[i][j] >= 0) {
				solver.add(id[i][0], id[j][1], a[i][j]);
			} else {
				solver.add(id[i][0], id[j][1], inf);
			}
		}
	}
	printf("%lld\n", s - solver.solve());
}

int main() {
	int T = 1;
	// scanf("%d", &T);
	while (T--) {
		solve();
	}
	return 0;
}

标签:AtCoder,Beginner,Contest,int,ll,flow,add,edges,sum
From: https://www.cnblogs.com/zltzlt-blog/p/17456488.html

相关文章

  • AtCoder Regular Contest 145
    A答案为Yes当且仅当$s[1]\ne$A或$s[n]\ne$B。注意判\(n=2\)。BAlice可胜利当且仅当\(n\gea\wedgen\bmoda<b\)。C显然我们应该凑\((2i-1,2i)\)。那么我们用一个括号序列描述\(2i-1\)和\(2i\),不难发现答案为\[\frac{\binom{2n}{n}}{n+1}......
  • AtCoder Beginner Contest 304 ABCDE
    AtCoderBeginnerContest304感觉手速场,后\(80\)分钟纯纯坐牢,A-FirstPlayer一些人坐成一个环,从年龄最小开始输出名字constintN=2e5+10;intn;strings[N];inta[N];voidsolve(){intm=1e9+2,p=1;cin>>n;for(inti=1;i<=n;......
  • AtCoder Beginner Contest 304
    A-FirstPlayer(abc304a)题目大意依次给定每个人的姓名和年龄,排成一圈。从年龄最小的人依次输出姓名。解题思路找到年龄最小的,依次输出就好了。神奇的代码#include<bits/stdc++.h>usingnamespacestd;usingLL=longlong;intmain(void){ios::sync_with_......
  • Beginner:Client libraries-10 创建并使用插件
    目标:学习创建和加载一个简单的插件使用pluginlib背景本教程来自于 http://wiki.ros.org/pluginlib and WritingandUsingaSimplePluginTutorial.pluginlib是一个c++库,用于从ROS包中加载和卸载插件。插件是从运行库(即共享对象、动态链接库)加载的可动态加载类。使用plugi......
  • Beginner:Client libraries-9 使用ros2doctor识别问题
    目标:在ros2系统中通过ros2doctor工具来识别问题。背景当ros2系统没有按预期运行,可以通过ros2doctor来检查设置。ros2doctor检查ros2的所有方面,包括平台,版本,网络,环境,运行系统等等,警告你可能的错误和问题的原因。ros2doctor是ros2cli的一部分。只要ros2cli按照常规安装,就可以使......
  • Beginner:Client libraries-8 在类中使用参数
    目标:创建和运行一个具有ROS参数的类背景当实现自己节点的时候,可能需要从launch文件中添加参数。本教程的目的是告诉你怎样在c++类中创建这些参数,以及怎样在launch文件中设置。任务1、创建一个包ros2pkgcreate--build-typeament_cmakecpp_parameters--dependenciesrcl......
  • Beginner:Client libraries-7实现自定义接口
    目标:在ROS2中学习更多的实现自定义接口背景在指定的接口包中声明接口,有时在一个包中声明、创建、使用所有接口很方便。本教程关注msg接口类型,但是步骤对于其他所有接口类型适用。任务1、创建一个包ros2pkgcreate--build-typeament_cmakemore_interfacesmkdirmore_in......
  • AtCoder Beginner Contest 286(G)
    AtCoderBeginnerContest286(G)G(欧拉路径)G题意大致为\(n\)个点,\(m\)个边的图,然后给出\(k\)条边的编号,问我们这\(k\)条边可不可以在一条路径上(每条边都可以经过)对于可不可以存在一条路径,里面包含个题目所给的\(k\)条边,其实就是问是否存在一条路可以经历这\(k\)条边,然后我们......
  • Beginner:Client libraries-3 创建一个包
    目标:使用CMake或者Python来创建一个新的包,运行可执行程序;背景1、ROS2的包是什么一个包是作为ROS2代码的组织单元。如果你想安装你的代码或与他人共享,那么你需要将其组织在一个包中。有了软件包,您可以发布您的ROS2作品,并允许其他人轻松构建和使用它。在ROS2中包的创建使用amen......
  • Beginner:Client libraries-2 创建工作空间
    目标:创建一个工作空间,学习如何设置开发和测试覆盖层(overlay)。背景工作空间是一个包含了ROS2的包的路径,在使用ros2之前首先需要source相应的ROS2工作空间来使用对应的包。overlay是一个可以添加新的包而不影响现有ROS2工作区,即underlay的工作空间;underlay中包含着overlay的依......