
壁纸链接
题目链接:https://atcoder.jp/contests/abc472/tasks
A - A
直接遍历字符串中的每个字符。如果当前字符为就保持不变,否则将其替换为,最后输出修改后的字符串即可。
void solve(){ string s; cin >> s; for(auto &it : s){ if(it != 'A'){ it = '.'; } } cout << s << endl;}B - Break a Stick
设所有部分的长度总和为,在第个切口折断时,左侧长度为前缀和,右侧长度为。两侧长度之差的绝对值为
。
我们先预处理前缀和,再枚举的所有合法切口,对上述差值取最小值即可。时间复杂度为,空间复杂度为。
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
按照题意顺序模拟,并用滑动窗口维护当前日期之前最近天内实际吃下的总热量。处理第天时,如果,就将第天标记为并把加入窗口;否则标记为,窗口总和不变。
完成当天判断后,如果当前窗口长度已经达到,就将最左端日期移出。只有该日期实际吃过时,它的热量才包含在中,所以代码使用记录每一天的选择,并在移出时判断是否需要减去。这样进入下一天前,恰好表示仍会影响下一次决策的日期范围。
每一天只会进入和移出窗口一次,时间复杂度为,空间复杂度为。由于和窗口和可能达到,需要使用保存。
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
首先确定所有安全空格。一个位置安全,当且仅当第行没有炸弹且第列没有炸弹。因此可以分别预处理所有无炸弹的行集合和列集合,全部安全空格正好是笛卡尔积。
接下来需要统计到安全空格的最短路不超过的空格。将所有安全空格同时加入队列并令距离为,执行一次多源。因为每次只能向上下左右的空格移动,且所有边权均为,多源得到的就是位置到最近安全空格的最少移动次数。搜索过程中不进入炸弹格,并且只扩展距离不超过的状态,最终访问到的格子数就是答案。
如果整个网格没有炸弹,那么每个格子本身都是安全空格,可以直接输出。安全空格数量至多为,因此总时间复杂度和空间复杂度均为。
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
无向图不存在奇环,当且仅当它是二分图。因此可以在过程中进行二染色:起点染为,每条树边的另一端染为相反颜色。如果遍历到一条连接同色顶点的边,就说明图中存在奇环;如果所有边都满足两端异色,则图是二分图,输出。
为了还原奇环,染色时同时记录树中的父节点和深度。找到同色边后,分别让沿父节点向上移动:先将深度较大的顶点提升到相同深度,再同步上移直到到达最近公共祖先。这个过程得到树上从到的唯一简单路径,最后再加上原图中的边就形成一个简单环。
由于颜色相同,它们的深度奇偶性相同,所以树上路径长度为偶数;再加上边后,环的边数以及顶点数均为奇数。代码将到最近公共祖先的路径存入,将侧路径反转后接到末尾,输出的顶点序列首尾通过冲突边相连。
每个顶点和每条边只会被遍历常数次,单个测试用例的时间复杂度为,空间复杂度为。题目保证图连通,因此从顶点开始一次即可覆盖全部顶点。
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 998244353typedef 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;}