2631 字
13 分钟
abc458
NOTE

比赛链接:Atcoder Beginner Contest 458

A - Chompers#

关键词:签到

Code#

// Problem: AT ABC458 A
// Contest: AtCoder - AtCoder Beginner Contest 458
// URL: https://atcoder.jp/contests/abc458/tasks/abc458_a
// Time: 2026-05-16 20:00:05
#include <bits/stdc++.h>
using namespace std;
// clang-format off
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define fastio() ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// clang-format on
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pll = pair<long long, long long>;
using i128 = __int128;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
const int inf = 0x3f3f3f3f;
const int N = 0;
void solve()
{
string s;
int n;
cin >> s >> n;
for (int i = n; i < s.size() - n; i++)
cout << s[i];
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

B - Count Adjacent Cells#

关键词:分类讨论

思路#

考虑讨论三种情况。当 nnmm 都为 11 时,答案是 00,当二者中有一个为 11 时,边界是单联通的,其余所有元素都是双联通。对于剩下的情况,四个角落是双联通,四条外侧边的中间部分是三联通,内部都是四联通。

Code#

// Problem: AT ABC458 B
// Contest: AtCoder - AtCoder Beginner Contest 458
// URL: https://atcoder.jp/contests/abc458/tasks/abc458_b
// Time: 2026-05-16 20:00:06
#include <bits/stdc++.h>
using namespace std;
// clang-format off
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define fastio() ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// clang-format on
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pll = pair<long long, long long>;
using i128 = __int128;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
const int inf = 0x3f3f3f3f;
const int N = 0;
int n, m;
bool check(int x, int y)
{
if (x == 1 && y == 1)
return true;
if (x == 1 && y == m)
return true;
if (x == n && y == 1)
return true;
if (x == n && y == m)
return true;
return false;
}
void solve()
{
cin >> n >> m;
if (n == 1 && m == 1)
{
cout << 0 << endl;
return;
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
{
if (n == 1 || m == 1)
{
if (check(i, j))
cout << 1 << " ";
else
cout << 2 << " ";
continue;
}
if (check(i, j))
{
cout << 2 << " ";
continue;
}
if (i == 1 || i == n || j == m || j == 1)
{
cout << 3 << " ";
continue;
}
cout << 4 << " ";
}
cout << endl;
}
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

C - C Stands for Center#

关键词:推公式

思路#

对于每个 CC,由于要求子区间长度为奇数,所以我们考虑以 CC 为中心向两侧扩展。容易知道,扩展的最远长度取决于它两侧元素数量的最小值,即 min(i, n - 1 - i)(下标从 00 开始)。

注意还要加 11,也就是不往外扩展的情况。此时子数组为 CC

Code#

// Problem: AT ABC458 C
// Contest: AtCoder - AtCoder Beginner Contest 458
// URL: https://atcoder.jp/contests/abc458/tasks/abc458_c
// Time: 2026-05-16 20:00:07
#include <bits/stdc++.h>
using namespace std;
// clang-format off
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define fastio() ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// clang-format on
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pll = pair<long long, long long>;
using i128 = __int128;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
const int inf = 0x3f3f3f3f;
const int N = 0;
void solve()
{
string s;
cin >> s;
ll n = s.size();
vector<ll> pos;
ll res = 0;
for (ll i = 0; i < s.size(); i++)
{
if (s[i] == 'C')
{
ll tmp = min(i, n - 1 - i);
res += tmp + 1;
}
}
cout << res << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

D - Chalkboard Median#

关键词:STL

思路#

一开始交了一发 TLETLE,考虑的是把所有数加入进一个 Multiset 里,并每次计算出中间位置的迭代器,但迭代器移动函数 advance()distance() 函数都是 O(n)O(n) 的,会超时。

我们考虑优化策略。注意到每次增加两个数,我们可以通过检验两个数和现有中间的数的大小关系。

假如现在集合里只有一个元素 xx,如果新加入两个比 xx 小的数,显然迭代器应该往左移动一个位置。同理,如果新加入两个比 xx 大(或者等于 xx)的数,迭代器应该往右移动一个位置。如果一大一小,迭代器保持不动即可。

NOTE

在 C++ 的 std::multiset 中,如果插入一个和已有元素相等的数,默认会把它插入到相同元素的最右侧

也就是说,如果 p == *it,它会被放到 it 的右边,不会影响 it 左侧的计数。

Code#

// Problem: AT ABC458 D
// Contest: AtCoder - AtCoder Beginner Contest 458
// URL: https://atcoder.jp/contests/abc458/tasks/abc458_d
// Time: 2026-05-16 20:00:08
#include <bits/stdc++.h>
using namespace std;
// clang-format off
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define fastio() ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// clang-format on
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pll = pair<long long, long long>;
using i128 = __int128;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
const int inf = 0x3f3f3f3f;
const int N = 0;
void solve()
{
int x, q;
cin >> x >> q;
multiset<int> s;
s.insert(x);
auto it = s.begin();
while (q--)
{
int p, y;
cin >> p >> y;
s.insert(p);
s.insert(y);
int cnt = 0;
if (p < *it)
cnt++;
if (y < *it)
cnt++;
if (cnt == 2)
--it;
else if (cnt == 0)
++it;
cout << *it << endl;
}
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

E - Count 123#

关键词:组合数学

思路#

注意到 22 是万能数字,我们考虑先排出一个只有 1133 的序列,在这个序列中 1133 允许相邻,但每一次相邻都必须在中间放入至少一个 22

假设我们排出的 13 序列中,恰好有 cc 个交界处(比如 1 1 3 1 中,13有 1 个,31有 1 个,共 2 个交界)。为了修复这 cc 个非法交界,我们必须强制消耗 cc2垫在中间。原本有 X2X_22,强制消耗了 cc 个,还剩 (X2c)(X_2 - c)​ 个 2

现在 13 的总数是 (X1+X3)(X_1 + X_3) 个,它们之间以及最左最右,一共提供了 (X1+X3+1)(X_1 + X_3 + 1) 个空位。

把剩下的 (X2c)(X_2 - c) 个相同的 2,放入这 (X1+X3+1)(X_1 + X_3 + 1) 个允许为空的槽位里,方案数为:

((X2c)+(X1+X3+1)1(X1+X3+1)1)=(X1+X2+X3cX1+X3)\binom{(X_2 - c) + (X_1 + X_3 + 1) - 1}{(X_1 + X_3 + 1) - 1} = \binom{X_1 + X_2 + X_3 - c}{X_1 + X_3}

下面我们考虑如何计算交界的数量。也就是有多少种排法,能让 13 产生恰好 cc 个交界?

我们设 kk 为一个基础块数,分奇偶讨论:

  • c=2k1c = 2k - 1(奇数个交界):

    序列一定是 1...33...1 这样交替。这意味着 1kk 个段,3 也有 kk 个段。

    X1X_1 分成 kk 段方案数是 (X11k1)\binom{X_1-1}{k-1},将 X3X_3 分成 kk 段是 (X31k1)\binom{X_3-1}{k-1}

    两种开头方式,总排法为:

    2×(X11k1)×(X31k1)2 \times \binom{X_1 - 1}{k - 1} \times \binom{X_3 - 1}{k - 1}

  • c=2kc = 2k(偶数个交界):

    序列一定是 1...13...3 这样交替。

    • 如果是 1...11k+1k+1 个段,3kk 个段。排法为 (X11k)×(X31k1)\binom{X_1-1}{k} \times \binom{X_3-1}{k-1}

    • 如果是 3...31kk 个段,3k+1k+1 个段。排法为 (X11k1)×(X31k)\binom{X_1-1}{k-1} \times \binom{X_3-1}{k}

      总排法就是这两者相加。

我们只需要枚举 kk,算出对应的 cc,把排法数 ×\times 剩下的随便放 2 的方案数累加起来即可。

Code#

// Problem: AT ABC458 E
// Contest: AtCoder - AtCoder Beginner Contest 458
// URL: https://atcoder.jp/contests/abc458/tasks/abc458_e
// Time: 2026-05-16 20:00:09
#include <bits/stdc++.h>
using namespace std;
// clang-format off
#define endl '\n'
#define all(x) (x).begin(), (x).end()
#define fastio() ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
// clang-format on
using ll = long long;
using ull = unsigned long long;
using pii = pair<int, int>;
using pdd = pair<double, double>;
using pll = pair<long long, long long>;
using i128 = __int128;
const int dx[] = {-1, 0, 1, 0, -1, 1, 1, -1};
const int dy[] = {0, 1, 0, -1, 1, 1, -1, -1};
const int inf = 0x3f3f3f3f;
const int N = 3e6 + 5;
using u32 = uint32_t;
using u64 = uint64_t;
template<class T>
constexpr T power(T a, u64 b, T res = 1)
{
for (; b != 0; b /= 2, a *= a)
{
if (b & 1)
res *= a;
}
return res;
}
template<class U, U P>
struct ModIntBase
{
public:
U x;
constexpr ModIntBase() : x(0)
{
}
constexpr ModIntBase(long long x_)
{
long long v = x_ % (long long) P;
if (v < 0)
v += (long long) P;
x = (U) v;
}
constexpr static U mod()
{
return P;
}
constexpr U val() const
{
return x;
}
constexpr ModIntBase operator-() const
{
return ModIntBase(x == 0 ? 0 : P - x);
}
constexpr ModIntBase inv() const
{
return power(*this, P - 2);
}
constexpr ModIntBase &operator*=(const ModIntBase &rhs) &
{
x = (u64) x * rhs.x % P;
return *this;
}
constexpr ModIntBase &operator+=(const ModIntBase &rhs) &
{
x += rhs.x;
if (x >= P)
x -= P;
return *this;
}
constexpr ModIntBase &operator-=(const ModIntBase &rhs) &
{
if (x < rhs.x)
x += P;
x -= rhs.x;
return *this;
}
constexpr ModIntBase &operator/=(const ModIntBase &rhs) &
{
return *this *= rhs.inv();
}
constexpr ModIntBase &operator++() &
{
x++;
if (x == P)
x = 0;
return *this;
}
constexpr ModIntBase &operator--() &
{
if (x == 0)
x = P;
x--;
return *this;
}
constexpr ModIntBase operator++(int)
{
ModIntBase res = *this;
++(*this);
return res;
}
constexpr ModIntBase operator--(int)
{
ModIntBase res = *this;
--(*this);
return res;
}
friend constexpr ModIntBase operator*(ModIntBase lhs, const ModIntBase &rhs)
{
return lhs *= rhs;
}
friend constexpr ModIntBase operator+(ModIntBase lhs, const ModIntBase &rhs)
{
return lhs += rhs;
}
friend constexpr ModIntBase operator-(ModIntBase lhs, const ModIntBase &rhs)
{
return lhs -= rhs;
}
friend constexpr ModIntBase operator/(ModIntBase lhs, const ModIntBase &rhs)
{
return lhs /= rhs;
}
friend istream &operator>>(istream &is, ModIntBase &a)
{
long long v;
is >> v;
a = ModIntBase(v);
return is;
}
friend ostream &operator<<(ostream &os, const ModIntBase &a)
{
return os << a.val();
}
friend bool operator==(const ModIntBase &lhs, const ModIntBase &rhs)
{
return lhs.val() == rhs.val();
}
friend bool operator!=(const ModIntBase &lhs, const ModIntBase &rhs)
{
return lhs.val() != rhs.val();
}
};
constexpr u32 MOD = 998244353;
using Z = ModIntBase<u32, MOD>;
struct Comb
{
int n;
vector<Z> _fac;
vector<Z> _invfac;
vector<Z> _inv;
Comb() : n(1), _fac(2), _invfac(2), _inv(2)
{
_fac[0] = _fac[1] = 1;
_invfac[0] = _invfac[1] = 1;
_inv[1] = 1;
}
Comb(int n) : Comb()
{
init(n);
}
void init(int m)
{
if (m <= n)
return;
int old = n;
_fac.resize(m + 1);
_invfac.resize(m + 1);
_inv.resize(m + 1);
for (int i = old + 1; i <= m; i++)
{
_fac[i] = _fac[i - 1] * i;
}
_invfac[m] = _fac[m].inv();
for (int i = m; i > old; i--)
{
_invfac[i - 1] = _invfac[i] * i;
_inv[i] = _invfac[i] * _fac[i - 1];
}
n = m;
}
Z fac(int m)
{
if (m > n)
init(2 * m);
return _fac[m];
}
Z invfac(int m)
{
if (m > n)
init(2 * m);
return _invfac[m];
}
Z inv(int m)
{
if (m > n)
init(2 * m);
return _inv[m];
}
Z binom(int n, int m)
{
if (m < 0 || m > n)
return 0;
return fac(n) * invfac(m) * invfac(n - m);
}
Z perm(int n, int m)
{
if (m < 0 || m > n)
return 0;
return fac(n) * invfac(n - m);
}
} comb;
void solve()
{
int x1, x2, x3;
cin >> x1 >> x2 >> x3;
comb.init(x1 + x2 + x3 + 5);
if (x1 == 0)
{
cout << comb.binom(x2 + x3, x3) << endl;
return;
}
if (x3 == 0)
{
cout << comb.binom(x1 + x2, x1) << endl;
return;
}
Z res = 0;
int lim = min(x1, x2 + 1);
for (int k = 1; k <= lim; k++)
{
Z a = comb.binom(x2 + 1, k);
Z b = comb.binom(x1 - 1, k - 1);
Z c = comb.binom(x2 + x3 - k, x3);
res += a * b * c;
}
cout << res << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}