← 全部文章

AtCoder Grand Contest 032 题解

本文目录(18 节)
  1. Limited Insertion
  2. Balanced Neighbors
  3. Three Circuits
  4. 题意
  5. 题解
  6. 代码
  7. Rotation Sort
  8. 题意
  9. 题解
  10. 代码
  11. Modulo Pairing
  12. 题意
  13. 题解
  14. 代码
  15. One Third
  16. 题意
  17. 题解
  18. 代码

AtCoder Grand Contest 032

Limited Insertion

倒着考虑,每次找到最大的 ii 满足 ai=ia_i = i 然后删掉,如果不存在则无解。

const int N = 107;
int n, a[N], ans[N];

int main() {
	rd(n), rda(a, n);
	for (int i = n; i; i--) {
		int p = 0;
		for (int j = i; j && !p; j--)
			if (a[j] == j) p = j;
		if (!p) return prints("-1"), 0;
		ans[i] = p;
		for (int j = p; j < i; j++) a[j] = a[j+1];
	}
	for (int i = 1; i <= n; i++) print(ans[i]);
	return 0;
}

Balanced Neighbors

构造方式见代码。

int main() {
	int n;
	rd(n);
	if (n == 3) {
		print(2);
		print(1, 3);
		print(2, 3);
		return 0;
	}
	if (n == 4) {
		print(4);
		print(1, 2);
		print(1, 3);
		print(4, 2);
		print(4, 3);
		return 0;
	}
	vector<pi> e;
	vi a, b;
	int m = n & 1;
	n -= m;
	for (int i = 1; i <= n >> 1; i++) a.pb(i);
	for (int i = n; i > n >> 1; i--) b.pb(i);
	for (int i = 1; i < n >> 1; i++)
		e.pb(mp(a[i-1], a[i])),
		e.pb(mp(b[i-1], b[i])),
		e.pb(mp(a[i-1], b[i])),
		e.pb(mp(b[i-1], a[i]));
	if (m) {
		e.pb(mp(n + 1, a[0])),
		e.pb(mp(n + 1, b[0])),
		e.pb(mp(n + 1, a.back())),
		e.pb(mp(n + 1, b.back()));
	} else {
		e.pb(mp(a.back(), a[0])),
		e.pb(mp(b.back(), b[0])),
		e.pb(mp(a.back(), b[0])),
		e.pb(mp(b.back(), a[0]));
	}
	print(e.size());
	for (pi o : e) print(o.fi, o.se);
	return 0;
}

Three Circuits

题意

  • 给定一张 nn 个点 mm 条边的无向图,问能否将无向图拆成三个环,使得每条边恰好在一个环中。
  • n,m≤105n,m \le 10^5。

题解

首先要是欧拉回路。

若度数最大值 ≥6\ge 6 则有解,=2= 2 则无解,接下来考虑 =4=4 的情况。

若度数为 44 的点超过 33 个则有解,11 个则无解,接下来考虑 22 个的情况。

只有两种形态,一种有解一种无解,讨论一下即可。

代码

const int N = 1e5 + 7;
int n, m, d[N], X, Y;
vi e[N];

void dfs(int x, int f) {
	if (x == Y) return;
	if (x == X) prints("Yes"), exit(0);
	for (int y : e[x])
		if (y != f) dfs(y, x);
}

int main() {
	rd(n, m);
	for (int i = 1, x, y; i <= m; i++)
		rd(x, y), ++d[x], ++d[y], e[x].pb(y), e[y].pb(x);
	for (int i = 1; i <= n; i++) if (d[i] & 1) return prints("No"), 0;
	int mx = *max_element(d + 1, d + n + 1);
	if (mx == 2) return prints("No"), 0;
	if (mx >= 6) return prints("Yes"), 0;
	int cnt = 0;
	for (int i = 1; i <= n; i++) cnt += d[i] == 4;
	if (cnt == 1) return prints("No"), 0;
	if (cnt >= 3) return prints("Yes"), 0;
	for (int i = 1; i <= n; i++)
		if (d[i] == 4) {
			if (X) Y = i;
			else X = i;
		}
	for (int z : e[X]) dfs(z, X);
	prints("No");
	return 0;
}

Rotation Sort

题意

  • 给定一个 1∼n1 \sim n 的排列 pp,你要将其变成升序。
  • 有两种操作:
    • 选择一个 l,rl,r 满足 1≤l<r≤n1 \le l < r \le n,将 pl…rp_{l\dots r} 替换为 pl+1…r,plp_{l+1\dots r},p_l,代价为 aa。
    • 选择一个 l,rl,r 满足 1≤l<r≤n1 \le l < r \le n,将 pl…rp_{l\dots r} 替换为 pr,pl…r−1p_{r},p_{l\dots r-1},代价为 bb。
  • 求最小代价。
  • n≤5×103n \le 5\times 10^3。

题解

显然操作等价于将某个数左移或者右移。

考虑 DP,设 fi,jf_{i,j} 表示考虑前 ii 个数,其中最后一个没有被移动的数为 jj 的最小代价,分 ai>ja_i > j 和 ai<ja_i < j 转移即可,时间复杂度 O(n2)\mathcal O(n^2)。

代码

const int N = 5e3 + 7;
const ll inf = 1e18;
int n, a, b, p[N];
ll f[N][N], ans = inf;

int main() {
	rd(n, a, b), rda(p, n);
	for (int i = 0; i <= n; i++)
		for (int j = 0; j <= n; j++)
			f[i][j] = inf;
	f[0][0] = 0;
	for (int i = 1; i <= n; i++)
		for (int j = 0; j <= n; j++)
			if (p[i] > j)
				f[i][j] = min(f[i][j], f[i-1][j] + a),
				f[i][p[i]] = min(f[i][p[i]], f[i-1][j]);
			else f[i][j] = min(f[i][j], f[i-1][j] + b);
	for (int i = 0; i <= n; i++) ans = min(ans, f[n][i]);
	print(ans);
	return 0;
}

Modulo Pairing

题意

  • 给定模数 mm 和 2n2n 个整数,你要将这些整数分成 nn 对。
  • 对于每一对 (x,y)(x,y),其权值为 (x+y) mod m(x+y) \bmod m。
  • 你要最小化这 nn 对权值的最大值。
  • n≤105n \le 10^5,m≤109m \le 10^9。

题解

有结论:按从小到大排序后,一定存在一个最优解,是以某个位置为界,两边分别首位匹配,满足左边每一对的和都 <m< m,右边每一对的和都 ≥m\ge m。

二分这个位置,时间复杂度 O(nlog⁡n)\mathcal O(n \log n)。

代码

const int N = 2e5 + 7;
int n, m, a[N], ans;

inline bool pd(int o) {
	for (int i = o << 1 | 1; i <= n << 1; i++)
		if (a[i] + a[((n+o)<<1|1)-i] < m) return 0;
	return 1;
}

int main() {
	rd(n, m), rda(a, n << 1);
	sort(a + 1, a + (n << 1 | 1));
	int l = 0, r = n;
	while (l < r) {
		int d = (l + r) >> 1;
		if (pd(d)) r = d;
		else l = d + 1;
	}
	int p = l << 1;
	for (int i = 1; i <= p; i++)
		ans = max(ans, a[i] + a[p+1-i]);
	for (int i = p + 1; i <= n << 1; i++)
		ans = max(ans, a[i] + a[(n<<1|1)+p-i] - m);
	print(ans);
	return 0;
}

One Third

题意

  • 有一个披萨,将它在 nn 条随机的半径切一刀。
  • 你会选择若干块相邻的披萨饼,使其总和最接近 13\frac 13。
  • 求选择的披萨饼大小与 13\frac 13 之差的绝对值的期望值。
  • n≤106n \le 10^6,答案对 109+710^9+7 取模。

题解

先转化,对于每一刀,先将其染成红色,再在 +13+ \frac 13 和 −13-\frac 13 各切一刀,分别染蓝色和绿色。

将每一刀  mod 13\bmod \frac 13,于是问题等价于有一条长 13\frac 13 的线段,00 处为红,13\frac 13 处为蓝,中间还有 n−1n-1 个位置和颜色随机的点,将整个线段分成了 nn 段,求最短的两端颜色不同的线段长度的期望。

把所有线段拿出来排序,考虑答案为第 kk 短的线段,经过积分可以得到为 ∑i=1k13n(n+1−i)\sum_{i=1}^{k} \frac{1}{3n(n+1-i)}。

考虑最短的,答案为 13n2\frac{1}{3n^2},如果同色考虑次短的,要加上 13n(n−1)\frac{1}{3n(n-1)} 乘上同色的概率 13\frac 13,以此类推,答案为 ∑k=1n13kn(n+1−k)\sum_{k=1}^{n} \frac{1}{3^kn(n+1-k)}。

时间复杂度 O(n)\mathcal O(n)。

代码

int n;
modint ans, a = 1;

int main() {
	rd(n), init(max(n, 3));
	for (int k = 1; k <= n; k++) ans += (a *= v[3]) * v[n+1-k];
	print(ans * v[n]);
	return 0;
}

标签:DP、二分、构造、概率期望、欧拉回路、组合计数、贪心

评论

    填写昵称即可留言。评论经站主审核后公开,请勿提交私人信息。

    正在连接评论服务…