「杂题乱写」AGC 004

「杂题乱写」AGC 004

点击查看目录


雪糕棒和我的订书器适配,好厉害!


下次放假把歌单搞进来,都不知道推什么歌了。

为了纪念昨天在我桌子上永远离开我们的苍蝇,今日推歌是 ilem 老师写的赤羽唱的《苍蝇》!

感觉词挺魔怔的。

点击查看歌词

猫可爱 狗可爱

全世界我最不可爱

春暖花开 你不期待

但我还是会回来 回来

什么仇什么怨

毁灭我与我不相干

你说因为你讨厌

但我只是想唱唱歌

我是病菌 你家就是我家

搓搓我的前爪 自己拿

我是命运 落在你的下巴

给你一个嘴巴 自己打

我是苍蝇 是卑劣的优雅

收集这世界的背面的残渣

啦啦啦啦啦以肮脏的名义

把世界净化

拿起武器

压倒性的辉煌的实力

你胜利 我死去

我在我尸体上站起站起

人类缺乏情趣

把决斗幸存当胜利

胜利当作正义

把正义当上帝

过度攫取 占有欲

去掠夺然后再舍弃

制造垃圾 消费意义

两败俱伤的胜利胜利

他带着荣耀死去

灵魂到天堂或地狱

但我哪儿也不去

我留在这里唱唱歌

我是轮回 翻飞我的翻飞

偷窥所有长夜的喜悲

你是人类 以为你的以为

你猜你的上帝 更爱谁

我是苍蝇 是黑色的标点

整理这世界的前后的章节

啦啦啦啦啦在王冠的下面

看英雄熄灭

我是病菌 是命运 是轮回

是翻飞的黑色的世界的标点

你是自称人类的谁

我是病菌 你家就是我家

搓搓我的前爪 自己拿

我是命运 落在你的下巴

给你一个嘴巴 自己打

我是苍蝇 是卑劣的优雅

收集这世界的背后的残渣

啦啦啦啦啦以肮脏的名义

把世界净化


本来是要打模拟赛的,但是水哥说我和 jijidawang 打过。

高一老哥最高分 140???

挂张高二人去年同一场模拟赛的图不多瑞平。

image


AGC 题目真挺小清新的。

一般来说只要有一个突破点就可以做出来,但是并不好想,感觉比较锻炼思维。

写题感觉思维上不去了可以来做做,挺愉悦身心的。

A | Divide a Cuboid

存在偶数可分成相等两块,不存在选两个乘积最小的。

B | Colorful Slimes

考虑枚举操作二次数。

WA 了一次,原因是 inf = 1ll << 40 不够大 😅

C | AND Grid

分别涂第一列和最后一列,奇数行和偶数行。

D | Teleporter

显然直接把 \(1\) 连向自己就可以。

然后把原图划分成多个子树连向 \(1\),每个子树深度不超过 \(k\)

点击查看代码
const ll N = 1e5 + 10;
namespace SOLVE {
	ll n, k, dep[N], vis[N], ans;
	std::vector <ll> tu[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void Dfs (ll u, ll fa) {
		far (v, tu[u]) {
			if (v == fa) continue;
			Dfs (v, u), dep[u] = std::max (dep[u], dep[v] + 1);
		}
		if (dep[u] == k - 1 && u != 1 && fa != 1) ++ans, dep[u] = -1;
		return;
	}
	inline void In () {
		n = rnt (), k = rnt (), ans = (rnt () != 1);
		_for (i, 2, n) tu[rnt ()].push_back (i);
		return;
	}
	inline void Solve () {
		Dfs (1, 0);
		return;
	}
	inline void Out () {
		printf ("%lld\n", ans);
		return;
	}
}

E | Salvage Robots

刚开始是觉得一个矩形只要不超过边界就都一定都可以到达出口。错的,有一个 Hack:

Hack 有乱劈的意思
5 5
.oo.o
..o.o
..oo.
E....
.o..o

正解是 DP。

\(f_{l, r, u, d}\) 表示清理过了左边 \(l\) 个方格,右边 \(r\) 个方格,上边 \(u\) 个方格,下边 \(d\) 个方格。

image

注意到移动后会有一些机器人被推出去(下图红框内的),转移时要判断一下。

image

\(s_{i1, j1, i2, j2}\) 表示左上角为 \((i1, j1)\),右下角为 \((i2, j2)\) 的矩形中有多少个机器人。

转移就是:

\[\begin{aligned} f_{l + 1, r, u, d} &\leftarrow \max \{f_{l + 1, r, u, d}, f_{l, r, u, d} + s_{\max \{i1 - 1, d\}, j1 - 1, \min \{i2, n - u\}, j1 - 1}\}\\ f_{l, r + 1, u, d} &\leftarrow \max \{f_{l, r + 1, u, d}, f_{l, r, u, d} + s_{\max \{i1 - 1, d\}, j2 + 1, \min \{i2, n - u\}, j2 + 1}\}\\ f_{l, r, u + 1, d} &\leftarrow \max \{f_{l, r, u + 1, d}, f_{l, r, u, d} + s_{i1 - 1, \max \{j1 - 1, r\}, i1 - 1, \min \{j2, m - l\}}\}\\ f_{l, r, u, d + 1} &\leftarrow \max \{f_{l, r, u, d + 1}, f_{l, r, u, d} + s_{i2 + 1, \max \{j1 - 1, r\}, i2 + 1, \min \{j2, m - l\}}\}\\ \end{aligned} \]

用下图感性理解:

image

点击查看代码
const ll N = 110;
namespace SOLVE {
	ll n, m, ex, ey, cnt[2][N][N], f[N][N][N][N], ans; char s[N][N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void In () {
		n = rnt (), m = rnt ();
		_for (i, 1, n) scanf ("%s", s[i] + 1);
		return;
	}
	inline void Solve () {
		_for (i, 1, n) {
			_for (j, 1, m) {
				if (s[i][j] == 'E') ex = i, ey = j;
				cnt[0][i][j] = cnt[0][i][j - 1] + (s[i][j] == 'o');
				cnt[1][i][j] = cnt[1][i - 1][j] + (s[i][j] == 'o');
			}
		}
		_for (l, 0, ey - 1) {
			_for (r, 0, m - ey) {
				_for (u, 0, ex - 1) {
					_for (d, 0, n - ex) {
						ans = std::max (ans, f[l][r][u][d]);
						ll i1 = ex - u, i2 = ex + d, j1 = ey - l, j2 = ey + r;
						if (l + r < ey - 1) f[l + 1][r][u][d] = std::max (f[l + 1][r][u][d], f[l][r][u][d] + cnt[1][std::min (i2, n - u)][j1 - 1] - cnt[1][std::max (i1 - 1, d)][j1 - 1]);
						if (l + r < m - ey) f[l][r + 1][u][d] = std::max (f[l][r + 1][u][d], f[l][r][u][d] + cnt[1][std::min (i2, n - u)][j2 + 1] - cnt[1][std::max (i1 - 1, d)][j2 + 1]);
						if (u + d < ex - 1) f[l][r][u + 1][d] = std::max (f[l][r][u + 1][d], f[l][r][u][d] + cnt[0][i1 - 1][std::min (j2, m - l)] - cnt[0][i1 - 1][std::max (j1 - 1, r)]);
						if (u + d < n - ex) f[l][r][u][d + 1] = std::max (f[l][r][u][d + 1], f[l][r][u][d] + cnt[0][i2 + 1][std::min (j2, m - l)] - cnt[0][i2 + 1][std::max (j1 - 1, r)]);
					}
				}
			}
		}
		return;
	}
	inline void Out () {
		printf ("%lld\n", ans);
		return;
	}
}

F | Namori

好难啊。好难啊。好难啊。好难啊。好难啊。好难啊。好难啊。好难啊。好难啊。

看 gtm1514 老师题解看懂的 /bx /bx /bx

这里就口胡一下,你要真想看懂就别看我的。

数据范围 \(N - 1\le M\le N\),所以图是一个树或基环树!

考虑转化题意,可以转化为把图黑白交替染色,于是操作就变成了交换黑白点,目标是黑白对调。

AGC 004 F

\(n\) 为奇数显然无解。

先从树入手。假设以 \(u\) 节点为根的子树有 \(x\) 个黑点,\(y\) 个白点,那么 \(u\) 通往父亲的边至少会被经过 \(a_u = \left|x - y\right|\) 次,求和即可。

然后考虑偶环基环树。我们断一条边,然后考虑环的贡献。操作 \(x\) 次这条边的话,环上会有一些边多向上跑 \(x\) 次,一些边多向下跑 \(x\) 次。维护一个 \(k\) 数组标记左右半环,断的边左端点标记 \(1\),右端点标记 \(-1\),环上答案应该是 \(\sum_{u\text{ on the ring}}\left|a_ik_i - x\right|\)

现在问题是 \(x\) 取什么能让这个式子值最小,答案是中位数。

最后考虑奇环基环树。染色后一定会有一条边两端点颜色相同,操作这条边相当于加上/减少两个黑点,那么设树上共有 \(x\) 个黑点,\(y\) 个白点,那么操作 \(\frac{\left|x - y\right|}{2}\) 次即可平衡黑白点数量。

注意到只有奇环基环树可以平衡黑白点数量,所以如果普通树/偶环基环树黑白点数量不一样也无解。

点击查看代码
const ll N = 1e5 + 10;
namespace SOLVE {
	ll n, m, c[N], zhiyin, e[2], k[N], ring[N], ans;
	std::vector <ll> tu[N];
	inline ll rnt () {
		ll x = 0, w = 1; char c = getchar ();
		while (!isdigit (c)) { if (c == '-') w = -1; c = getchar (); }
		while (isdigit (c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getchar ();
		return x * w;
	}
	inline void Paint (ll u, ll fa, ll color) {
		c[u] = color;
		far (v, tu[u]) {
			if (v == fa) continue;
			if (!c[v]) Paint (v, u, -color);
			else {
				if (c[u] == c[v]) zhiyin = 1;
				e[0] = u, e[1] = v;
			}
		}
		return;
	}
	inline void GetAns (ll u, ll fa) {
		far (v, tu[u]) {
			if (v == fa || (u == e[0] && v == e[1]) || (u == e[1] && v == e[0])) continue;
			GetAns (v, u), c[u] += c[v], k[u] += k[v];
		}
		return;
	}
	inline void In () {
		n = rnt (), m = rnt ();
		_for (i, 1, m) {
			ll u = rnt (), v = rnt ();
			tu[u].push_back (v);
			tu[v].push_back (u);
		}
		return;
	}
	inline void Solve () {
		if (n & 1) { ans = -1; return; }
		Paint (1, 0, 1);
		ll cnt = 0;
		_for (i, 1, n) cnt += c[i];
		if (m == n - 1 && cnt) { ans = -1; return; }
		if (m == n) {
			if (zhiyin) ans += std::abs (cnt / 2), c[e[0]] -= cnt / 2, c[e[1]] -= cnt / 2;
			else  {
				if (cnt) { ans = -1; return; }
				else k[e[0]] = 1, k[e[1]] = -1;
			}
		}
		GetAns (1, 0);
		_for (i, 1, n) {
			if (k[i]) ring[++ring[0]] = c[i] * k[i];
			else ans += std::abs (c[i]);
		}
		ring[++ring[0]] = 0;
		std::sort (ring + 1, ring + ring[0] + 1);
		ll mid = ring[(ring[0] + 1) >> 1];
		_for (i, 1, ring[0]) ans += std::abs (ring[i] - mid);
		return;
	}
	inline void Out () {
		printf ("%lld\n", ans);
		return;
	}
}
posted @ 2023-06-11 15:26  K8He  阅读(92)  评论(7编辑  收藏  举报