首页 > 其他分享 >AtCoder Beginner Contest 227 H Eat Them All

AtCoder Beginner Contest 227 H Eat Them All

时间:2023-06-28 18:35:34浏览次数:47  
标签:AtCoder Them Beginner int flow ++ pb 99 edges

洛谷传送门

AtCoder 传送门

好奇特的题。

考虑显式建图,那么这是一个 \(9\) 个结点,\(12\) 条边的图,需要找到一条回路使得第 \(i\) 个点被经过 \(a_i\) 次。

首先会有一个基本思路:先求出每条边经过的次数,然后每条边复制这么多次即可直接构造欧拉回路。其中每条边经过次数的限制就是,每个点连出去的边,经过次数之和等于 \(2 \times a_i\),并且去掉没经过的边,图仍然连通。

考虑直接暴力枚举图的一棵生成树,钦定这些边至少被经过 \(1\) 次,然后在这个二分图上跑最大流,判断最大流是否为 \(\sum a_i\) 即可得知是否合法。

还有一种做法是,列出 \(9\) 个 \(12\) 元一次方程组,暴力枚举自由元的值判断。

code
// Problem: H - Eat Them All
// Contest: AtCoder - KEYENCE Programming Contest 2021 (AtCoder Beginner Contest 227)
// URL: https://atcoder.jp/contests/abc227/tasks/abc227_h
// 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<int, int> pii;

const int inf = 0x3f3f3f3f;

int a[99], b[99], head[99], len, S, T, ntot, fa[99], id[99];
struct edge {
	int to, next, cap, flow;
} edges[9999];

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

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

int find(int x) {
	return fa[x] == x ? x : fa[x] = find(fa[x]);
}

inline bool merge(int x, int y) {
	x = find(x);
	y = find(y);
	if (x != y) {
		fa[x] = y;
		return 1;
	} else {
		return 0;
	}
}

int p[9999], tot;
vector<pii> G[99];
bool vis[9999];

void dfs(int u) {
	for (pii p : G[u]) {
		int v = p.fst, id = p.scd;
		if (!vis[id]) {
			vis[id] = 1;
			dfs(v);
		}
	}
	p[++tot] = u;
}

void solve() {
	int s0 = 0, s1 = 0;
	for (int i = 0; i < 3; ++i) {
		for (int j = 0, x; j < 3; ++j) {
			scanf("%d", &x);
			a[i * 3 + j] = x * 2;
			if ((i + j) & 1) {
				s1 += a[i * 3 + j];
			} else {
				s0 += a[i * 3 + j];
			}
		}
	}
	if (s0 != s1) {
		puts("NO");
		return;
	}
	vector<pii> E;
	E.pb(0, 1);
	E.pb(1, 2);
	E.pb(3, 4);
	E.pb(4, 5);
	E.pb(6, 7);
	E.pb(7, 8);
	E.pb(0, 3);
	E.pb(3, 6);
	E.pb(1, 4);
	E.pb(4, 7);
	E.pb(2, 5);
	E.pb(5, 8);
	for (int S = 1; S < (1 << 12); ++S) {
		if (__builtin_popcount(S) != 8) {
			continue;
		}
		for (int i = 0; i < 9; ++i) {
			fa[i] = i;
			b[i] = a[i];
			vector<pii>().swap(G[i]);
		}
		bool flag = 0;
		for (int i = 0; i < 12; ++i) {
			if ((~S) & (1 << i)) {
				continue;
			}
			if (!merge(E[i].fst, E[i].scd)) {
				flag = 1;
				break;
			}
			--b[E[i].fst];
			--b[E[i].scd];
		}
		for (int i = 0; i < 9; ++i) {
			if (b[i] < 0) {
				flag = 1;
				break;
			}
		}
		if (flag) {
			continue;
		}
		len = 1;
		mems(head, 0);
		ntot = 8;
		::S = ++ntot;
		T = ++ntot;
		for (int i = 0; i < 12; ++i) {
			int u = E[i].fst, v = E[i].scd;
			if (u & 1) {
				solver.add(v, u, inf);
			} else {
				solver.add(u, v, inf);
			}
			id[i] = len - 1;
		}
		for (int i = 0; i < 9; ++i) {
			if (i & 1) {
				solver.add(i, T, b[i]);
			} else {
				solver.add(::S, i, b[i]);
			}
		}
		int flow = solver.solve();
		if (flow + 8 != s0) {
			continue;
		}
		mems(vis, 0);
		int tt = 0;
		for (int i = 0; i < 12; ++i) {
			int k = ((S >> i) & 1) + edges[id[i]].flow, u = E[i].fst, v = E[i].scd;
			for (int j = 0; j < k; ++j) {
				G[u].pb(v, ++tt);
				G[v].pb(u, tt);
			}
		}
		dfs(0);
		reverse(p + 1, p + tot + 1);
		for (int i = 1; i < tot; ++i) {
			if (p[i + 1] == p[i] + 1) {
				putchar('R');
			} else if (p[i + 1] == p[i] - 1) {
				putchar('L');
			} else if (p[i + 1] == p[i] + 3) {
				putchar('D');
			} else {
				putchar('U');
			}
		}
		return;
	}
	puts("NO");
}

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

标签:AtCoder,Them,Beginner,int,flow,++,pb,99,edges
From: https://www.cnblogs.com/zltzlt-blog/p/17512221.html

相关文章

  • AtCoder Beginner Contest 306(ABC 306) E~F补题
    E题目大意给定数字$k$,规定数组$A$的函数$f(A)$:$A$数组前$k$大数字的和如$A=[1,3,7,~4]$,$k=2$,则$f(A)=7+4=11$现在给定最大数组长度$n$,有$q$组操作,每次将第$x$个数字修改为$y$,输出每次操作后的$f(A)$其中$0<k\leqn\leq5\times10^5,~q\leq5\times......
  • AtCoder Beginner Contest 228 G Digits on Grid
    洛谷传送门AtCoder传送门?这啥啊,不会。考虑行和列分别作为左部点和右部点建二分图(实际上这个建图只是辅助理解,不需要显式建图),每个左部点和每个右部点,边权为格子中的数。容易想到一个dp,设\(f_{i,j}\)为走了\(i\)步,当前在点\(j\),走过的所有边权组成的不同整数的数量。但......
  • 【五期邹昱夫】CCF-A(NeurIPS'22)Trap and Replace: Defending Backdoor Attacks by Tra
    "Wang,Haotao,etal."TrapandReplace:DefendingBackdoorAttacksbyTrappingThemintoanEasy-to-ReplaceSubnetwork."AdvancesinNeuralInformationProcessingSystems."  本文提出一种基于图像生成网络的后门攻击防御方法。该方法将图像分类模型分成特征......
  • AtCoder Beginner Contest 072
    A-Sandglass2#include<bits/stdc++.h>usingnamespacestd;#defineintlonglongint32_tmain(){inta,b;cin>>a>>b;cout<<max(a-b,0ll);return0;}B-OddString#include<bits/stdc++.h>......
  • AtCoder Beginner Contest 238 Ex Removing People
    洛谷传送门AtCoder传送门考虑期望转计数,方案数显然是\(n!\)(第\(i\)次操作有\(n-i+1\)个人可供选择),所以问题转化为求所有方案的代价之和。考虑倒着做,变成先放一个人,然后依次放\(n-1\)个人,每次放的这个人可以让左边的人的\(S\)变成R,代价是他与他左边的人的距离,......
  • AtCoder Beginner Contest 307 Ex Marquee
    洛谷传送门AtCoder传送门一开始看错题了,看了好久才发现就是个板子。。。这个东西本质上是循环移位,我们考虑在\(S\)前后各添加\(W-1\)个.,例如\(W=5,S=\texttt{ABC}\)时,添加后\(S=\texttt{....ABC....}\)。此时我们发现\(S\)的每个长度为\(W\)的子串一一对......
  • AtCoder Beginner Contest(abc) 307
    A-WeeklyRecords题目大意小莫每天跑步,输入n周每天的步数,输出每周跑的总步数;解题思路签到题不多嗦了;神秘代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intn,m,k,idx;signedmain(){ cin>>n; intsum=0; for(inti......
  • AtCoder Beginner Contest 307 G Approximate Equalization
    洛谷传送门AtCoder传送门考虑我们如果确定了最终态\(B=(B_1,B_2,...,B_n)\),如何计算最少操作次数。显然从左往右依次使\(A_i=B_i\)。当操作到第\(i\)个位置时,此时\(A'_i=\sum\limits_{j=1}^iA_j-B_j\),所需操作次数为\(|A'_i|\)。令\(C_i=\sum\limits_{......
  • AtCoder Beginner Contest 245 Ex Product Modulo 2
    洛谷传送门AtCoder传送门很好的题。下文令\(k\)为原题面中的\(n\),\(n\)为原题面中的\(k\),\(m\)为原题面中的\(m\)。从一些简单的情况入手。1.\(m\)为质数\(k=0\)的情况是平凡的,只需要要求\(\existsi\in[1,n],a_i=0\)即可。总方案数减去不合法方案数,......
  • AtCoder Beginner Contest 307 ABCDE
    AtCoderBeginnerContest307A-WeeklyRecordsProblemStatement题意:告诉你有几个礼拜,问你每个礼拜走的路程和。Solution思路:按题意模拟,每7天加起来就行。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;intmain(){ intn; cin>>n; llsum=......