562 字
1 分钟
Atcoder_Beginner_Contest_461(A~D题)
2026-06-07
浏览量 146 · 访客 12

题目链接:https://atcoder.jp/contests/abc461/tasks

A - Armor#

按照题意判断输出即可。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define endl '\n'
#define mod 998244353
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
void solved(){
int a, d;
cin >> a >> d;
if(a > d) cout << "No" << endl;
else cout << "Yes" << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_--){
solved();
}
return 0;
}

B - The Honest Woodcutters#

我们判断每个伐木工ii拥有的斧头是否是他自己的(b[a[i]]b[a[i]]是否等于ii)即可,如果有一个不是那就输出nono,否则就yesyes

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define endl '\n'
#define mod 998244353
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
int a[110];
int b[110];
void solved(){
int n;
cin >> n;
for(int i = 1; i <= n;i++) cin >> a[i];
for(int i = 1; i <= n;i++) cin >> b[i];
for(int i = 1; i <= n;i++){
if(b[a[i]] != i){
cout << "No" << endl;
return;
}
}
cout << "Yes" << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_--){
solved();
}
return 0;
}

C - Variety#

这里的思路是将每个颜色宝石中价值最大的放入数组max_valsmax\_vals,然后取最大的mm个计入总价值,也就是满足了mm个颜色种类这个条件。然后max_valsmax\_vals里面没选到的元素就放入other_valsother\_vals。和其他宝石一起排序,然后再取价值最大的kk - mm个宝石取够kk个宝石计入总价值即可。

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define endl '\n'
#define mod 998244353
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
map<ll, vector<ll>> mp;
vector<ll> max_vals;
vector<ll> other_vals;
void solved(){
int n, k, m;
cin >> n >> k >> m;
for(int i = 1; i <= n;i++){
ll c, v;
cin >> c >> v;
mp[c].push_back(v); //用二维数组计入对应颜色c含有的所有价值v
}
//将map中的数组元素从大到小排序
for(auto &c : mp){
sort(c.second.begin(), c.second.end(), greater<ll>());
}
for(auto it1 : mp){
ll cnt = 1;
for(auto it2 : it1.second){
if(cnt){max_vals.push_back(it2),cnt--;continue;} //max_vals只取每个颜色的第一个
other_vals.push_back(it2); //其他就加入other_vals
}
}
//排序之后取前m个
sort(max_vals.begin(), max_vals.end(), greater<ll>());
ll cnt = 0;
ll ans = 0;
for(auto it : max_vals){
if(cnt < m){
ans += it;
cnt++;
}
else other_vals.push_back(it);
}
//排序之后取前k - m个
sort(other_vals.begin(), other_vals.end(), greater<ll>());
for(auto it : other_vals){
if(cnt != k){
ans += it;
cnt++;
}
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_--){
solved();
}
return 0;
}

D - Count Subgrid Sum = K#

这题直接暴力的复杂度会达到O(H2W2)O(H^2 W^2),没办法通过这题。思路是通过给定确定的矩阵上界和下界,然后再在上下界里取左右边界,然后统计矩阵内计数之和为kk的个数即为答案。这个原理的复杂度大概为O(H2W)O(H^2 W),足够通过本题。
这里上下界的循环仍然有H2H^2的复杂度,优化的地方是在给定上下界的每一列中计算整一列的整数之和,然后将WW个列压成了一维数组columncolumn,求连续子序列之和为kk的数量有多少个。这里的解法是利用前缀和变式。我们知道pre[r+1]pre[l]=kpre[r + 1] - pre[l] = k[l,r][l, r]就是满足条件的区间。我们不妨改变一下式子。变成pre[l]=pre[r+1]kpre[l] = pre[r + 1] - k,也就是说,对于目前遍历到的前缀和prefix(pre[r+1])prefix(pre[r + 1]),满足条件的区间的数量就是pre[l]pre[l]的出现频率(prefixL_cnt)(prefixL\_cnt)。所以每次遍历时我们累加对应的prefixL_cntprefixL\_cnt即可。不过这里要注意prefixL_cnt[0]prefixL\_cnt[0]要设置成11,以正确统计区间左端点ll00的区间。(这里的prefixL_cntprefixL\_cnt数组是base0base-0的)
这里的touchedtouched是为了记录每一次给定上下界的循环内使用到的prefixL_cnt[i]prefixL\_cnt[i],然后一一对应清零,供下一次循环使用。(如果使用直接将prefixL_cnt[i]prefixL\_cnt[i]全部覆写为00的话需要写入HWH \cdot W次,可能超时,所以只把用到清零即可)

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
#define endl '\n'
#define mod 998244353
typedef pair<ll, ll> pll;
typedef pair<int, int> pii;
vector<string> grid;
vector<int> column, prefixL_cnt, touched;
void solved(){
int h, w, k;
ll ans = 0;
cin >> h >> w >> k;
grid.resize(h + 1);
column.resize(w + 1);
prefixL_cnt.resize(h * w + 10);
for(int i = 1; i <= h;i++){
cin >> grid[i];
grid[i] = " " + grid[i];
}
//上界
for(int i = 1; i <= h;i++){
//清空column
fill(column.begin(), column.end(), 0);
//下界
for (int j = i; j <= h;j++){
//压缩为一维数组
for(int l = 1; l <= w;l++){
column[l] += grid[j][l] - '0';
}
//当前的前缀和
int prefix = 0;
prefixL_cnt[0] = 1;
touched.push_back(0);
for(int i = 1; i <= w;i++){
prefix += column[i];
if(prefix >= k) ans += prefixL_cnt[prefix - k]; //统计满足条件的区间
if(prefixL_cnt[prefix] == 0) touched.push_back(prefix); //第一次出现时计入touched中
prefixL_cnt[prefix]++;
}
//只清空用过的prefixL_cnt[x]
for(int x : touched){
prefixL_cnt[x] = 0;
}
touched.clear();
}
}
cout << ans << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
// cin >> _;
while(_--){
solved();
}
return 0;
}
分享

如果这篇文章对你有帮助,欢迎分享给更多人!

Atcoder_Beginner_Contest_461(A~D题)
https://mkrari.cn/posts/abc_461/
作者
Mkrari
发布于
2026-06-07
许可协议
CC BY-NC-SA 4.0