AtCoder Regular Contest 解题报告

好久没写 At 题解了,而且从来没写过 ARC 的题解,今天就来写一发。

这场是我有史以来表现分最高的一场,唯一可惜的就是考场上没时间写 E 了,不然差不多能进前 100。

A - Three Integers

题目链接

题意简述

给你三个数 \(A, B, C \in [0,10^{18}]\)
你可以做以下两种操作:

  • 选其中两个数,让它们减去 \(1\)
  • 让全部三个数减去 \(1\)

问最少几步可以让这三个数都变成 \(0\)

解体思路

贪心,尽可能多地用操作 \(2\)
由于操作顺序无关紧要,我们先做完所有的操作 \(2\)
接下来只用操作 \(1\),容易发现当且仅当 \(A+B+C\equiv0 \pmod 2\) 并且 \(A,B,C\) 中较小的两个数之和大于等于最大的数时,只用操作 \(1\) 有解。
然后嗯做就可以了,懒得再写了,具体看代码吧。

参考代码

#include <vector>
#include <iostream>
#include <algorithm>

using i64 = long long;
using vint = std::vector<int>;
using PII = std::pair<int, int>;

int main(void)
{
	//Think twice, code once.
	std::ios::sync_with_stdio(false);
	i64 a[3];
	std::cin >> a[0] >> a[1] >> a[2];
	i64 x = a[0] + a[1] + a[2];
	std::sort(a, a + 3);
	i64 res = 0;
	if (x & 1) {
		++res;
		for (int i = 0; i < 3; ++i)
			--a[i];
	}
	if (a[0] < 0) {
		puts("-1");
		return 0;
	}
	i64 k = (a[0] + a[1] - a[2]);
	if (k < 0) {
		puts("-1");
		return 0;
	}
	k = k / 2 * 2;
	res += k;
	for (int i = 0; i < 3; ++i)
		a[i] -= k;
	res += (a[0] + a[1] + a[2]) / 2;
	std::cout << res << '\n';
	return 0;
}

B - Counting Grids

题目链接

题意简述

给定一个 \(n \in [1,500]\),你要把 \(1\sim n^2\) 填入 大小为 \(n \times n\) 的方阵中,满足对于任意一个格子,至少满足以下两个条件之一:

  • 不是它所在列的最小值。
  • 不是它所在行的最大值。

问有多少种方案,对 \(998244353\) 取模。

解体思路

明显很难直接求,考虑相反的情况:
存在一个格子,它是所在列的最小值,也是所在行的最大值。
反证法容易证明这种格子不可能同时存在两个,那我们直接枚举这个格子的值,设其为 \(x\),它的位置有 \(n^2\) 种,它所在列只能有比他大的值,所以只有 \({x - 1\choose n-1} \times (n - 1)!\) 种可能,同列它所在列只有 \({n - x \choose n - 1} \times (n - 1)!\) 种可能,其余数可以随意排列,有 \((n^2 - 2n + 1)!\) 种可能。综上,相反情况的方案数就是

\[\sum_{x=1}^{n^2}n^2\times{x - 1\choose n-1} \times (n - 1)!\times{n - x \choose n - 1} \times (n - 1)!\times(n^2 - 2n + 1)! \]

\((n^2)!\) 减去上述式子即为答案。

参考代码

#include <vector>
#include <iostream>
#include <algorithm>

using i64 = long long;
using vint = std::vector<int>;
using PII = std::pair<int, int>;
const int N = 500 * 500 + 10, mod = 998244353;
inline int Mod(int x) { return x >= mod ? x - mod : x; }

struct ModInt
{
	int val;
	ModInt(void) { val = 0; }
	ModInt(int x) { val = x; }
	ModInt operator+(const ModInt &other) const
	{ return Mod(val + other.val); }
	ModInt operator-(const ModInt &other) const
	{ return Mod(val + mod - other.val); }
	ModInt operator*(const ModInt &other) const
	{ return 1ll * val * other.val % mod; }
};

ModInt fac[N], inv[N];
inline ModInt qpow(ModInt base, int k)
{
	ModInt res = 1;
	while (k) {
		if (k & 1) res = res * base;
		k >>= 1;
		base = base * base;
	}
	return res;
}
inline ModInt getInv(ModInt x) { return qpow(x, mod - 2); }
inline ModInt C(int n, int m)
{
	if (n < m || n < 0 || m < 0) return 0;
	return fac[n] * inv[m] * inv[n - m];
}

int main(void)
{
	//Think twice, code once.
	std::ios::sync_with_stdio(false);
	fac[0] = 1;
	for (int i = 1; i < N; ++i)
		fac[i] = fac[i - 1] * i;
	inv[N - 1] = getInv(fac[N - 1]);
	for (int i = N - 2; i >= 0; --i)
		inv[i] = inv[i + 1] * (i + 1);

	int n; std::cin >> n;
	ModInt res;
	for (int i = 1; i <= n * n; ++i) {
		ModInt o = n * n;
		o = o * C(i - 1, n - 1) * fac[n - 1];
		o = o * C(n * n - i, n - 1) * fac[n - 1];
		o = o * fac[n * n - (n + n - 1)];
		res = res + o;
	}
	std::cout << (fac[n * n] - res).val << '\n';
	return 0;
}

C - Piles of Pebbles

题目链接

题意简述

\(n\) 堆石子,第 \(i\) 堆包含 \(A_i\) 个石子。
Takahashi 和 Aoki 将会进行一场游戏,规则如下:

  • 两人轮流行动,Takahashi 先走,第一个无法行动的人失败。
  • 轮到 Takahashi 时,Takahashi 选择至少一堆包含大于等于 \(X\) 个石子的石子堆,把它们都移去 \(X\) 个石子。
  • 轮到 Aoki 时,Aoki 选择至少一堆包含大于等于 \(Y\) 个石子的石子堆,把它们都移去 \(Y\) 个石子。

问先手是否必胜。

解体思路

参考代码

D - Three Integers

题目链接

题意简述

解体思路

参考代码

E - Three Integers

题目链接

题意简述

解体思路

参考代码

F - Counting Subsets

没看,不会

posted @ 2022-07-03 21:25  LroseC  阅读(142)  评论(0)    收藏  举报