2359 字
12 分钟
abc461
NOTE

比赛链接:Atcoder Beginner Contest 461

A - Armor#

关键词:签到

Code#

// Problem: AT ABC461 A
// Contest: AtCoder - AtCoder Beginner Contest 461
// URL: https://atcoder.jp/contests/abc461/tasks/abc461_a
// Time: 2026-06-06 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()
{
int a, d;
cin >> a >> d;
cout << (a <= d ? "Yes" : "No") << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

B - The Honest Woodcutters#

关键词:签到

Code#

// Problem: AT ABC461 B
// Contest: AtCoder - AtCoder Beginner Contest 461
// URL: https://atcoder.jp/contests/abc461/tasks/abc461_b
// Time: 2026-06-06 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 n;
cin >> n;
vector<int> a(n + 1), b(n + 1);
map<int, int> mp;
for (int i = 1; i <= n; ++i)
{
cin >> a[i];
mp[a[i]] = i;
}
for (int i = 1; i <= n; ++i)
{
cin >> b[i];
if (mp[i] != b[i])
{
cout << "No" << endl;
return;
}
}
cout << "Yes" << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

C - Variety#

关键词:贪心

思路#

首先这不是一个dp题。

考虑首先把所有的宝石按价值从大到小排序,贪心地拿最大的前 kk 个宝石,并且记录不同颜色的数量。

当不同的颜色不够 mm 种时,我们就要继续拿其他颜色的最大价值的宝石,由于前面排序过,如果当前宝石是一种尚未出现的新颜色,那么它一定是这种颜色中价值最大的宝石,就应该直接把它加进来,那我们怎么从现有的宝石里找一个去掉呢?

对于当前已经选中的宝石:

  • 如果某颗宝石是其颜色唯一的一颗,那么删除它会使颜色种类减少 11,不能随意删除;
  • 如果某颗宝石的颜色已经出现过,那么它是重复颜色的宝石,删除它不会减少颜色种类。

因此,只有重复颜色宝石可以被替换。为了使损失尽可能小,我们应当优先删除价值最小的重复颜色宝石。

可以使用一个小根堆,维护所有可删除宝石的价值。

Code#

// Problem: AT ABC461 C
// Contest: AtCoder - AtCoder Beginner Contest 461
// URL: https://atcoder.jp/contests/abc461/tasks/abc461_c
// Time: 2026-06-06 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 = 2e5 + 10;
struct Gems
{
int c;
ll v;
bool operator<(const Gems &other) const
{
return v > other.v;
}
} g[N];
void solve()
{
int n, k, m;
cin >> n >> k >> m;
for (int i = 0; i < n; ++i)
cin >> g[i].c >> g[i].v;
sort(g, g + n);
vector<bool> st(n + 1, false);
priority_queue<ll, vector<ll>, greater<ll>> heap;
ll res = 0;
int colors = 0;
for (int i = 0; i < k; ++i)
{
auto &[c, v] = g[i];
res += v;
if (!st[c])
st[c] = true, colors++;
else
heap.push(v);
}
for (int i = k; i < n && colors < m; ++i)
{
auto &[c, v] = g[i];
if (st[c])
continue;
res -= heap.top();
heap.pop();
res += v;
st[c] = true;
colors++;
}
cout << res << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

D - Count Subgrid Sum = K#

关键词:暴力

思路#

这里是天堂吗?为什么在D题出现了一个可以用 O(n4)O(n^4) 来过的算法?

二维前缀和暴力算即可。自己都没想到过了。

好吧,时限竟然是4s,为什么过的人这么少?

Code#

// Problem: AT ABC461 D
// Contest: AtCoder - AtCoder Beginner Contest 461
// URL: https://atcoder.jp/contests/abc461/tasks/abc461_d
// Time: 2026-06-06 20:00:10
#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 = 510;
int g[N][N], s[N][N];
void solve()
{
int h, w, k;
cin >> h >> w >> k;
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
{
char ch;
cin >> ch;
g[i][j] = ch - '0';
}
for (int i = 1; i <= h; ++i)
for (int j = 1; j <= w; ++j)
s[i][j] = s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1] + g[i][j];
ll res = 0;
for (int x1 = 1; x1 <= h; x1++)
for (int x2 = x1; x2 <= h; x2++)
for (int y1 = 1; y1 <= w; y1++)
for (int y2 = y1; y2 <= w; y2++)
if (s[x2][y2] - s[x2][y1 - 1] - s[x1 - 1][y2] + s[x1 - 1][y1 - 1] == k)
res++;
cout << res << endl;
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

E - E-liter#

关键词:树状数组

思路#

转化题意#

注意到行永远只会被染成黑色,列永远只会被染成白色。

这意味着,对于网格中的任意一个细胞 (r,c)(r, c),我们根本不需要知道它经历了多少次反复横跳。它的最终颜色只取决于一件事:行 rr 和 列 cc 谁最后被操作过

可以使用时间戳来记录。定义 rowrrow_r 为第 rr 行最后一次被涂黑的时间,colccol_c 为第 cc 列最后一次被涂白的时间。

初始时所有格子为白色,可以让 rowr=colc=0row_r=col_c=0,当第 ii 次操作发生时,将它的时间记为 ii

对于格子 (r,c)(r,c)

  • rowr>colcrow_r > col_c,说明最近一次相关操作是行涂黑,格子为黑色;
  • rowrcolcrow_r \leq col_c,说明列涂白操作更新,或者从未被染黑,格子为白色。

因此:(r,c) 为黑色    rowr>colc(r,c) \text{ 为黑色} \iff row_r > col_c

考虑单次操作如何修改答案:关键在于每次操作只需要计算这一行或这一列原来有多少个黑色格子。

操作 11:将第 RR 行涂黑。执行操作前,第 RR 行中的格子 (R,c)(R, c) 为黑色,当且仅当 colc<rowRcol_c < row_R,因此这一行原本的黑色格子数量为:old=#{ccolc<rowR}old = \#\{c \mid col_c < row_R\}。即统计所有满足 colc<rowRcol_c < row_R 的格子 cc 的数量。执行操作后,第 RR 行的所有 NN 个格子都会变成黑色,所以答案增加 NoldN-old,随后更新时间戳。

操作 22:将第 CC 列涂白。执行操作前,第 CC 行中的格子 (r,C)(r, C) 为黑色,当且仅当 rowr>colCrow_r > col_C,因此这一列原本的黑色格子数量为:old=#{crowr>colC}old = \#\{c \mid row_r > col_C\},执行操作后,这一列的所有格子都会变成白色。所以答案减少 oldold,随后更新时间戳。

维护信息#

每次查询需要快速回答两类问题:

  1. 有多少个 colc<xcol_c < x
  2. 有多少个 rowr>xrow_r > x

可以使用树状数组维护每一种时间戳出现了多少次。

建立两个树状数组,bitrbitr 表示每一种时间戳对应多少行,bitcbitc 表示每一种时间戳对应多少列。

总结#

NOTE

这类题目的关键特征是:

  • 对整行、整列、区间或区域执行覆盖操作;

  • 后执行的操作会覆盖先执行的操作;

  • 需要实时统计满足某种条件的元素数量。

  • 此时可以优先考虑:将覆盖关系转换为最后操作时间的大小比较。

Code#

NOTE

代码实现方面:由于树状数组不能使用下标 00,所以初始时间戳都设置为 11,第一次查询对应时间戳 22

// Problem: AT ABC461 E
// Contest: AtCoder - AtCoder Beginner Contest 461
// URL: https://atcoder.jp/contests/abc461/tasks/abc461_e
// Time: 2026-06-06 20:00:11
#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 = 3e5 + 10;
struct Fenwick
{
int n;
vector<ll> tr;
Fenwick()
{
}
Fenwick(int n)
{
init(n);
}
Fenwick(const vector<ll> &a)
{
build(a);
}
void init(int n)
{
this->n = n;
tr.assign(n + 1, 0);
}
int lowbit(int x)
{
return x & -x;
}
void build(const vector<ll> &a)
{
init(static_cast<int>(a.size()) - 1);
for (int i = 1; i <= n; i++)
{
tr[i] += a[i];
int j = i + lowbit(i);
if (j <= n)
tr[j] += tr[i];
}
}
void add(int x, ll val)
{
for (int i = x; i <= n; i += lowbit(i))
tr[i] += val;
}
ll sum(int x)
{
ll res = 0;
for (int i = x; i > 0; i -= lowbit(i))
res += tr[i];
return res;
}
ll range_sum(int l, int r)
{
return sum(r) - sum(l - 1);
}
};
void solve()
{
int n, q;
cin >> n >> q;
vector<int> row(n + 1, 1), col(n + 1, 1);
Fenwick bitr(q + 1), bitc(q + 1);
bitr.add(1, n), bitc.add(1, n);
ll res = 0;
for (int t = 2; t <= q + 1; t++)
{
ll op, x;
cin >> op >> x;
if (op == 1)
{
int old = bitc.sum(row[x] - 1);
res += n - old;
bitr.add(row[x], -1);
row[x] = t;
bitr.add(row[x], 1);
}
else
{
int old = n - bitr.sum(col[x]);
res -= old;
bitc.add(col[x], -1);
col[x] = t;
bitc.add(col[x], 1);
}
cout << res << endl;
}
}
int main()
{
fastio();
int T = 1;
// cin >> T;
while (T--)
solve();
return 0;
}

评论