1051 字
3 分钟
Atcoder_Beginner_Contest_472(A~E题)
2026-08-24
浏览量 27 · 访客 10

壁纸链接
题目链接:https://atcoder.jp/contests/abc472/tasks

A - A#

直接遍历字符串中的每个字符。如果当前字符为AA就保持不变,否则将其替换为..,最后输出修改后的字符串即可。

void solve(){
string s; cin >> s;
for(auto &it : s){
if(it != 'A'){
it = '.';
}
}
cout << s << endl;
}

B - Break a Stick#

设所有部分的长度总和为sumsum,在第ii个切口折断时,左侧长度为前缀和preipre_i,右侧长度为sumpreisum-pre_i。两侧长度之差的绝对值为 prei(sumprei)=2preisum|pre_i-(sum-pre_i)|=|2pre_i-sum|
我们先预处理前缀和,再枚举i=1,2,,N1i=1,2,\ldots,N-1的所有合法切口,对上述差值取最小值即可。时间复杂度为O(N)O(N),空间复杂度为O(N)O(N)

void solve(){
int n; cin >> n;
int ans = 1e9, sum = 0;
vector<int> pre(n + 1, 0), suf(n + 1, 0);
for(int i = 1; i <= n;i++) {
int x; cin >> x;
pre[i] = pre[i - 1] + x;
sum += x;
}
for(int i = 1; i < n;i++){
ans = min(ans, abs(2 * pre[i] - sum));
}
cout << ans << endl;
}

C - On a Diet#

按照题意顺序模拟,并用滑动窗口维护当前日期之前最近M1M-1天内实际吃下的总热量sumsum。处理第ii天时,如果sum+AiKsum+A_i\leq K,就将第ii天标记为YesYes并把AiA_i加入窗口;否则标记为NoNo,窗口总和不变。
完成当天判断后,如果当前窗口长度已经达到MM,就将最左端日期移出。只有该日期实际吃过时,它的热量才包含在sumsum中,所以代码使用visvis记录每一天的选择,并在移出时判断是否需要减去AleftA_{left}。这样进入下一天前,sumsum恰好表示仍会影响下一次决策的日期范围。
每一天只会进入和移出窗口一次,时间复杂度为O(N)O(N),空间复杂度为O(N)O(N)。由于KK和窗口和可能达到101510^{15},需要使用long longlong\ long保存。

void solve(){
int n, m; ll k; cin >> n >> m >> k;
vector<ll> a(n + 1, 0);
vector<bool> vis(n + 1, false);
for(int i = 1; i <= n;i++) cin >> a[i];
int left = 1;ll sum = 0;
for(int i = 1; i <= n;i++){
if(i - left + 1 <= m){
if(sum + a[i] <= k){
sum += a[i];
vis[i] = true;
}
if(i - left + 1 == m){
if(vis[left] == true)
sum -= a[left];
left++;
}
}
}
for(int i = 1; i <= n;i++){
if(vis[i]) cout << "Yes" << '\n';
else cout << "No" << '\n';
}
}

D - Bomber Mad#

首先确定所有安全空格。一个位置(i,j)(i,j)安全,当且仅当第ii行没有炸弹且第jj列没有炸弹。因此可以分别预处理所有无炸弹的行集合RR和列集合CC,全部安全空格正好是笛卡尔积R×CR\times C
接下来需要统计到安全空格的最短路不超过KK的空格。将所有安全空格同时加入队列并令距离为00,执行一次多源BFSBFS。因为每次只能向上下左右的空格移动,且所有边权均为11,多源BFSBFS得到的dist[i][j]dist[i][j]就是位置(i,j)(i,j)到最近安全空格的最少移动次数。搜索过程中不进入炸弹格,并且只扩展距离不超过KK的状态,最终访问到的格子数就是答案。
如果整个网格没有炸弹,那么每个格子本身都是安全空格,可以直接输出H×WH\times W。安全空格数量至多为H×WH\times W,因此总时间复杂度和空间复杂度均为O(HW)O(HW)

int dx[5] = {0, 1, 0, 0, -1};
int dy[5] = {0, 0, 1, -1, 0};
void solve(){
int H, W, K;
cin >> H >> W >> K;
bool has_boom = false;
vector<string> grid(H + 1);
for(int i = 1; i <= H;i++){
cin >> grid[i];
grid[i] = " " + grid[i];
if(grid[i].find('#') != grid[i].npos)
has_boom = true;
}
if(!has_boom){
cout << H * W << endl;
return;
}
vector<int> q1, q2;
for(int i = 1; i <= H;i++){
bool h = true;
for(int j = 1; j <= W;j++){
if(grid[i][j] == '#') h = false;
}
if(h) q1.push_back(i);
}
int ans = 0;
for(int i = 1; i <= W;i++){
bool w = true;
for(int j = 1; j <= H;j++){
if(grid[j][i] == '#') w = false;
}
if(w) q2.push_back(i);
}
queue<pii> q;
vector<vector<int>> dist(H + 1, vector<int>(W + 1, -1));
for(int i = 0; i < (int)q1.size();i++){
for(int j = 0; j < (int)q2.size();j++){
int a = q1[i], b = q2[j];
dist[a][b] = 0;
q.push({a, b});
}
}
while(!q.empty()){
auto [x, y] = q.front();
q.pop();
if(dist[x][y] > K) continue;
ans++;
for(int i = 1; i <= 4;i++){
int tx = x + dx[i];
int ty = y + dy[i];
if(tx >= 1 && tx <= H && ty >= 1 && ty <= W && dist[tx][ty] == -1 && grid[tx][ty] != '#'){
dist[tx][ty] = dist[x][y] + 1;
if(dist[tx][ty] <= K)
q.push({tx, ty});
}
}
}
cout << ans << endl;
}

E - Odd Cycle#

无向图不存在奇环,当且仅当它是二分图。因此可以在BFSBFS过程中进行二染色:起点染为11,每条树边的另一端染为相反颜色。如果遍历到一条连接同色顶点U,VU,V的边,就说明图中存在奇环;如果所有边都满足两端异色,则图是二分图,输出1-1
为了还原奇环,染色时同时记录BFSBFS树中的父节点fafa和深度depdep。找到同色边(U,V)(U,V)后,分别让U,VU,V沿父节点向上移动:先将深度较大的顶点提升到相同深度,再同步上移直到到达最近公共祖先。这个过程得到BFSBFS树上从UUVV的唯一简单路径,最后再加上原图中的边(V,U)(V,U)就形成一个简单环。
由于U,VU,V颜色相同,它们的深度奇偶性相同,所以树上路径长度为偶数;再加上边(U,V)(U,V)后,环的边数以及顶点数均为奇数。代码将UU到最近公共祖先的路径存入path1path1,将VV侧路径反转后接到末尾,输出的顶点序列首尾通过冲突边相连。
每个顶点和每条边只会被遍历常数次,单个测试用例的时间复杂度为O(N+M)O(N+M),空间复杂度为O(N+M)O(N+M)。题目保证图连通,因此从顶点11开始一次BFSBFS即可覆盖全部顶点。

void solve(){
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1);
for(int i = 1; i <= m;i++){
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
}
vector<int> color(n + 1, 0), fa(n + 1, 0), dep(n + 1, 0);
int U = -1, V = -1;
queue<int> q;
color[1] = 1, fa[1] = 0;
dep[1] = 0, q.push(1);
while(!q.empty() && U == -1){
int u = q.front();
q.pop();
for(auto v : g[u]){
if(color[v] == 0){
color[v] = -color[u];
fa[v] = u;
dep[v] = dep[u] + 1;
q.push(v);
}
else if(color[v] == color[u]){
U = u;
V = v;
break;
}
}
}
if(U == -1){cout << -1 << '\n'; return;}
int u = U, v = V;
vector<int> path1, path2;
while(dep[u] > dep[v]){
path1.push_back(u); u = fa[u];
}
while(dep[v] > dep[u]){
path2.push_back(v); v = fa[v];
}
while(u != v){
path1.push_back(u), path2.push_back(v);
u = fa[u], v = fa[v];
}
path1.push_back(u);
reverse(path2.begin(), path2.end());
cout << (int)path1.size() + (int)path2.size() << '\n';
for(auto it : path1) cout << it << " ";
for(auto it : path2) cout << it << " ";
cout << '\n';
}

模板:

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = unsigned long long;
#define mod 998244353
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;
ll fast_pow(ll a, ll b, ll MOD){
ll ans = 1;
while(b){
if(b & 1) ans = (ans * a) % MOD;
b >>= 1;
a = (a * a) % MOD;
}
return ans;
}
vector<ll> get_inverse(ll n, ll MOD){
vector<ll> inverse(n + 1, 0);
inverse[1] = 1;
for(int i = 2; i <= n;i++){
inverse[i] = MOD - (MOD / i) * inverse[MOD % i] % MOD;
}
return inverse;
}
void solve(){
}
int main(){
ios::sync_with_stdio(false),
cin.tie(nullptr), cout.tie(nullptr);
int _ = 1;
//cin >> _;
while(_--){
solve();
}
return 0;
}
分享

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

Atcoder_Beginner_Contest_472(A~E题)
https://mkrari.cn/posts/abc_472/
作者
Mkrari
发布于
2026-08-24
许可协议
CC BY-NC-SA 4.0