ABC285

发布时间 2023-07-17 23:12:10作者: HQJ2007

[ABC285D] Change Usernames

依据题意直接连边,判断有没有环即可。

复杂度 \(O(n)\)

[ABC285E] Work or Rest

我们可以发现,相对位置一定的选法不会对答案造成影响,所以我们可以考虑第一天必选。

然后就是一个很经典的 DP 了。

定义 \(f_i\) 为第 \(i\) 天选,前 \(i\) 天最大的工作量。\(sum_i\)\(\sum\limits_{i=1}^{i}a_i\)

\[f_i=\max(f_j+\operatorname{val}(i,j)) \]

其中:

\[\operatorname{val}(i,j)=\begin{cases}2\times sum_{r-mid-1}+a_{r - mid}&2\vert (r-l)\\2\times sum_{r-mid-1} &else\end{cases} \]

最后枚举所选的最后一天,然后把剩下的一段加入贡献并取最大值即可。

复杂度 \(O(n^2)\)

[ABC285F] Substring of Sorted String

有趣的好题。

对于这类问题,我们首先可以想到用线段树来维护。

区间 \([l,r]\) 满足要求,当且仅当满足以下两点:

  1. 不降。

  2. 区间 \([1,l)\)\((r,n]\) 中的字符没有大于 \(c_l\) 且小于 \(c_r\) 的情况。

对于第一个条件,我们可以用线段树实时维护一个差分数组,每次查询 \((l,r]\) 中的最小值是否为负即可,注意 \(l\) 不取。

对于第二个条件,我们可以开 \(26\) 个树状数组分别记录每种字符的出现情况。枚举 \((c_l,c_r)\) 中的字符是否在 \([1,l)\)\((r,n]\) 中出现过,如果出现过,则答案为 No

复杂度 \(O(n\log n)\)

[ABC285G] Tatami

有源汇上下界网络流。

首先我们要搞明白无源汇上下界网络流问题怎么处理。

以下部分参考 OI-wiki。

定义一条边的下界为 \(b(u,v)\),上界为 \(a(u,v)\)

不妨假设这条边已经流过了 \(b(u,v)\),设其为初始流。然后我们要进行一些调整使得该图满足平衡条件,即每个点入流出流相同。

假设一个点初始流入流量减初始流出流量为 \(M\)

\(M=0\),此时流量平衡,不需要附加边。

\(M>0\),此时入流量过大,需要新建附加源点 \(S'\)\(S'\) 向其连流量为 \(M\) 的附加边。

\(M<0\),此时出流量过大,需要新建附加汇点 \(T'\),其向 \(T'\) 连流量为 \(-M\) 的附加边。

如果附加边满流,则说明平衡条件可以满足。

所以最后跑一边从 \(S'\)\(T'\) 的最大流即可。

有源汇上下界网络流基本类似,只需要对于其初始原点 \(S\) 和汇点 \(T\) 连一条 \((T, S, inf)\) 即可。

回到这道题。

对于 \(1\),我们直接不管。

对于 \(2\)\(?\),我们四个方向连边。

然后可以考虑给棋盘黑白染色,黑色连向 \(S\),白色连向 \(T\)

对于 \(2\) ,向 S 和 T 连边的时候设其下界为 \(1\),顺便记录一下初始流 \(in\)\(out\)

最后对于每个点根据 \(in_i-out_i\) 的值添加附加边即可。

注意,一定要把 dinic 的所有优化加上,少一个都会 T,不要问我怎么知道的。

#include <bits/stdc++.h>
using namespace std;
const int N = 300 + 5, N2 = 3e6 + 5, inf = INT_MAX >> 2; 
int n, m, s, t, head[N2], nex[N2], to[N2], val[N2], dep[N2], in[N2], out[N2], cur[N2];
int dx[] = {0, 0, -1, 1}, dy[] = {-1, 1, 0, 0};
int tot = 1;
char c[N][N];
queue<int> q;
int d(int i, int j) {return (i - 1) * m + j;}
void add(int u, int v, int w) {
	val[++tot] = w;
	to[tot] = v;
	nex[tot] = head[u];
	head[u] = tot;
	val[++tot] = 0;
	to[tot] = u;
	nex[tot] = head[v];
	head[v] = tot;
}
int bfs() {
	for (int i = 1; i <= t; ++i) dep[i] = 0;
	dep[s] = 1; q.push(s); cur[s] = head[s];
	while (!q.empty()) {
		int u = q.front(); q.pop();
		for (int i = head[u]; i; i = nex[i]) {
			int v = to[i];
			if (val[i] > 0 && !dep[v]) {
				dep[v] = dep[u] + 1;
				cur[v] = head[v];
				q.push(v);
			}
		}
	}
	return dep[t];
}
int dfs(int u, int cc) {
	if (u == t) return cc;
	int out_ = 0;
	for (int i = cur[u]; i && cc; i = nex[i]) {
		cur[u] = i;
		int v = to[i];
		if (val[i] && dep[v] == dep[u] + 1) {
			int tmp = dfs(v, min(val[i], cc));
			val[i] -= tmp; val[i ^ 1] += tmp; cc -= tmp; out_ += tmp;
		}
	}
	if (!out_) dep[u] = 0;
	return out_;
}
int main() {
	ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
	cin >> n >> m; s = n * m + 1; t = s + 1;
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) {
		cin >> c[i][j];
		if (c[i][j] == '?') {
			if (i + j & 1) add(s, d(i, j), 1);
			else add(d(i, j), t, 1);
		} if (c[i][j] == '2') {
			if (i + j & 1) ++out[s], ++in[d(i, j)];
			else ++out[d(i, j)], ++in[t];
		}
	}
	for (int i = 1; i <= n; ++i) for (int j = 1; j <= m; ++j) if (c[i][j] != '1' && (i + j & 1)) {
		for (int k = 0; k < 4; ++k) {
			int tx = i + dx[k], ty = j + dy[k];
			if (tx < 1 || ty < 1 || tx > n || ty > m || c[tx][ty] == '1') continue;
			add(d(i, j), d(tx, ty), 1);
		}
	}
	add(t, s, inf);
	s = s + 2; t = t + 2;
	int sum = 0;
	for (int i = 1; i <= n * m + 2; ++i) {
		if (in[i] > out[i]) sum += in[i] - out[i], add(s, i, in[i] - out[i]);
		if (out[i] > in[i]) add(i, t, out[i] - in[i]);
	}
	int ans = 0;
	while (bfs()) ans += dfs(s, inf); 
	if (ans >= sum) cout << "Yes" << endl;
	else cout << "No" << endl; 
	return 0;
}