AtCoder Beginner Contest 427 ABCDEF 题目解析

news/2025/10/11 23:16:58/文章来源:https://www.cnblogs.com/stelayuri/p/19136124

A - ABC -> AC

题意

给定一个长度为奇数且仅由大写字母组成的字符串 \(S\)

请删除该字符串正中间的字符,再输出该字符串。

代码

void solve()
{string s;cin >> s;for(int i = 0; i < s.size(); i++)if(i != s.size() / 2)cout << s[i];
}

B - Sum of Digits Sequence

题意

定义 \(f(x)\) 表示 \(x\) 在十进制下的数位和。

通过以下方法定义一个无限长度的序列 \(A=(A_0, A_1, A_2, \dots)\)

  • \(A_0 = 1\)
  • \(A_i = \sum\limits_{j=0}^{i-1} f(A_j), \quad (i \ge 1)\)

给定一个正整数 \(N\),请求出 \(A_N\) 的值。

思路

\(N\) 较小,直接模拟公式的计算方法即可。

代码

int f(int n)
{int res = 0;while(n > 0){res += n % 10;n /= 10;}return res;
}void solve()
{int n;cin >> n;int a[105];a[0] = 1;for(int i = 1; i <= n; i++){a[i] = 0;for(int j = 0; j < i; j++)a[i] += f(a[j]);}cout << a[n];
}

C - Bipartize

题意

给定一张 \(N\) 个点 \(M\) 条边的简单无向图,每个点分别编号为 \(1, 2, \dots, N\),第 \(i\) 条边连接 \(u_i, v_i\) 这两个点。

你会执行以下操作零次或多次:

  • 选择一条尚未删除的边,然后将其删除。

你的目标是让这张图最终成为一张二分图,并求出满足目标的最少操作数。

思路

注意到本题的 \(N\) 较小,可以尝试借助深度优先搜索/二进制枚举来找出最终每种可能的二分图分组方案。

\(N\) 个点分为两组后,求出所有边中连接同一组内的点的边数,取个最小值即为答案。

时间复杂度 \(O((N+M)\cdot 2^N)\)

代码一 深搜

int n, m;
int u[50], v[50];
int ans = 1e9;
int gp[15]; // gp[i] 表示 i 点的组别void dfs(int p)
{if(p > n){int cnt = 0; // 连接同组点的边数for(int i = 1; i <= m; i++)if(gp[u[i]] == gp[v[i]])cnt++;ans = min(ans, cnt);return;}// 尝试把 p 点分到 1 组内gp[p] = 1;dfs(p + 1);// 尝试把 p 点分到 2 组内gp[p] = 2;dfs(p + 1);
}void solve()
{cin >> n >> m;for(int i = 1; i <= m; i++)cin >> u[i] >> v[i];dfs(1);cout << ans << "\n";
}

代码二 二进制枚举

int n, m;
int u[50], v[50];
int gp[15];void solve()
{cin >> n >> m;for(int i = 1; i <= m; i++)cin >> u[i] >> v[i];int ans = m;for(int sta = 0; sta < (1 << n); sta++){// sta 的二进制表示分组状态for(int i = 1; i <= n; i++)gp[i] = (sta >> (i - 1) & 1); // 把分组情况提出来int cnt = 0; // 连接同组点的边数for(int i = 1; i <= m; i++){if(gp[u[i]] == gp[v[i]]) // u[i] 和 v[i] 在同一组内cnt++;}ans = min(ans, cnt);}cout << ans << "\n";
}

D - The Simple Game

题意

给定一张 \(N\) 个点 \(M\) 条边的有向图,每个点编号分别为 \(1, 2, \dots, N\),第 \(i\) 条边是从点 \(U_i\) 连向点 \(V_i\) 的有向边。保证每个点的出度至少为 \(1\)

每个点上都有一个字符,第 \(i\) 个点上的字符为 \(S_i\)

Alice 和 Bob 正使用一枚棋子在这张图中玩游戏:

  • 最初,该棋子被放在点 \(1\) 上,然后他们两人会交替进行 \(K\) 轮游戏,每轮 Alice 先进行,Bob 后进行。

    • \(u\) 表示当前棋子所在顶点的编号。每次每人可以选择一个点 \(v\) 并将棋子移动到该点处,但必须要保证 \(u\)\(v\) 之间存在一条有向边。
  • \(v\) 表示最终棋子所在顶点的编号。如果 \(S_v = \texttt{A}\),则 Alice 获胜;如果 \(S_v = \texttt{B}\),则 Bob 获胜。

若两人均以最优策略进行游戏,请问最终的获胜者是谁。

思路

因为最终获胜者一定是确定的,必胜的状态在游戏过程中不会改变,因此可以考虑借助动态规划倒推必胜态。

由于题意中的 \(K\) 轮表示 \(K\) 个来回,实际上两人总共执行了 \(2K\) 次操作,下文以 \(2K\) 来表示操作数。

定义 dp[i][j] 表示第 \(j\) 次操作结束后,如果棋子来到了 \(i\) 这个点,接下来谁会赢。(\(1/2\) 分别表示 Alice/Bob 的必胜态。)

一开始能够确定的必胜态一定是在游戏结束的时候,也就是当第 \(2K\) 次操作结束后,如果棋子来到 \(i\) 这个点,那么根据该点上的字符 \(S_i\) 可以直接确定这个状态是谁赢。因此动态规划的初始状态 dp[i][2*k] 可以直接求出。

考虑倒推每一次操作 \(j = 2K-1 \sim 0\),然后对于图中的每一个点 \(i\),状态 dp[i][j] 表示的是谁的必胜态,取决于下一步的操作者能否把棋子移动到他自己的必胜态上。

下一步的操作者可以根据当前操作次数 \(j\) 的奇偶性判断出来,这里我们假设下一步的操作者是 Bob,那么他的任务就是对于所有从 \(i\) 出发能够到达的下一个点 \(v\),然后看看在所有 dp[v][j+1] 中,是否存在至少一个状态能够保证他必赢。如果有,那么当前的 dp[i][j] 就表示他必赢,这里我们记 dp[i][j] = 2 即可;如果没有,说明下一步的必胜态全都是 Alice 的,记 dp[i][j] = 1。如果下一步操作者是 Alice 同理。

最后只需要检查在一次操作也没有进行,且棋子位于点 \(1\) 时的必胜态指向谁即可,也就是 dp[1][0] 的值。

单组数据时间复杂度 \(O(K\cdot (N+M))\)

代码

int dp[200005][21];
// dp[i][j] 表示第 j 次操作结束后如果来到 i 这个点,谁会赢 1-Alice 2-Bob
vector<int> G[200005];void solve()
{int n, m, k;cin >> n >> m >> k;string s;cin >> s;for(int i = 1; i <= n; i++){G[i].clear();for(int j = 0; j <= 2 * k; j++)dp[i][j] = 0;if(s[i - 1] == 'A')dp[i][2 * k] = 1; // 如果最后一次操作站在 i 点上,则 Alice 必赢elsedp[i][2 * k] = 2; // 如果最后一次操作站在 i 点上,则 Bob 必赢}for(int i = 1; i <= m; i++){int u, v;cin >> u >> v;G[u].push_back(v);}for(int j = 2 * k - 1; j >= 0; j--) // 倒推每次操作{for(int i = 1; i <= n; i++) // 如果第 j 次操作结束时站在 i 点上{bool alice = false, bob = false; // 判断下一步是否能够移动到 alice/bob 必赢的状态上for(int &v : G[i]){if(dp[v][j + 1] == 1)alice = true;elsebob = true;}if((j + 1) % 2 == 0) // 如果下一步是 Bob 移动{if(bob) // 并且下一步能够移动到 Bob 必赢的点上dp[i][j] = 2;else // 如果不能,则当前状态表示 Alice 赢dp[i][j] = 1;}else // 同上,如果下一步是 Alice 移动{if(alice)dp[i][j] = 1;elsedp[i][j] = 2;}}}if(dp[1][0] == 1) // 一开始站在 1 号点上,且未进行操作的必胜态cout << "Alice\n";elsecout << "Bob\n";
}signed main()
{int t;cin >> t;while(t--)solve();return 0;
}

E - Wind Cleaning

题意

有一个 \(H \times W\) 的网格图。定义 \((i, j)\) 表示上到下第 \(i\) 行,左到右第 \(j\) 列的单元格。

高桥在这个网格图中的某个单元格上,并且某些单元格上存在一些垃圾。

单元格的状态由 \(H\) 个长度为 \(W\) 的字符串给出,第 \(i\) 个字符串的第 \(j\) 个字符记作 \(S_{i, j}\)

  • 如果 \(S_{i, j} =\) T,则单元格 \((i, j)\) 表示高桥一开始的位置。
  • 如果 \(S_{i, j} =\) #,则单元格 \((i, j)\) 存在垃圾。
  • 如果 \(S_{i, j} =\) .,则单元格 \((i, j)\) 是一个空单元格。

高桥一开始的位置没有垃圾。

每次高桥可以重复执行以下操作:

  • 选择上、下、左、右四个方向之一,然后将所有垃圾同时朝着该方向移动一个单元格。如果垃圾在本次操作中被移出了这个网格图,那么这个垃圾就会永远消失;而如果垃圾移动到高桥所在的位置,那么他就会变脏。

请帮助高桥判断是否有可能在不弄脏他自己的前提下让所有垃圾都消失。如果可能,求最少的操作次数。

思路

题目中提到,如果垃圾被移出网格图,就相当于永远消失了。又因为每次我们会移动所有的垃圾,所以垃圾的消除肯定是整行或者整列一起消除的。

因为消除后相当于原本的这一整行或整列直接没有垃圾了,所以我们可以简单地当作这一整行或整列成为了网格图外的一部分,而我们的网格图每次移动后都会缩小

例如:让所有垃圾往左移动一格,相当于是垃圾不动,而高桥以及地图的左边界全部往右移动了一格。

于是我们便可以在地图不移动的情况下,通过维护当前地图可行部分的上、下、左、右边界以及高桥的位置,来借助宽搜对问题进行求解。

在这种思路下,高桥的坐标可能会超出地图边界,并且在离开地图范围时可能地图内还存在垃圾,需要继续移动。发现高桥在 \(x, y\) 方向的坐标变化量只会在 \([-H, H], [-W, W]\) 以内,如果超出此范围,那么地图内的可行部分便全部消失了,此时所有垃圾肯定都已经被移除。

方便起见,我们可以新定义一个坐标系,把高桥一开始的坐标定作 \((H, W)\),让其移动范围不超出 \(0 \sim 2H\) 以及 \(0 \sim 2W\) 来防止越界,在过程中根据其移动的位置顺便更新实际可行边界即可。

最后,只要可行边界内不存在任何垃圾,搜索就可以结束,说明找到了终点。这一步可以借助二位前缀和等方法快速求解范围内的垃圾数量。

时间复杂度 \(O(H^3\cdot W^3)\)

代码

int n, m;
char mp[14][14];int s[14][14]; // 二位前缀和,表示左上角有多少垃圾struct point
{int t, b, l, r; // 上、下、左、右 边界相对于原地图的位置int x, y, step; // 高桥当前位置 及 移动次数
};
queue<point> q;
bool vis[14][14][14][14][28][28];void solve()
{cin >> n >> m;int sx, sy;for(int i = 1; i <= n; i++)for(int j = 1; j <= m; j++){cin >> mp[i][j];s[i][j] = s[i-1][j] + s[i][j-1] - s[i-1][j-1] + (mp[i][j] == '#' ? 1 : 0);if(mp[i][j] == 'T')sx = i, sy = j;}q.push(point{1, n, 1, m, n, m}); // 高桥的起始位置假设是 (n, m),平移防止越界vis[1][n][1][m][n][m] = true;while(!q.empty()){point u = q.front();q.pop();for(int i = 0; i < 4; i++){point v = u;v.step++;v.x += dx[i];v.y += dy[i];v.t = max(v.t, v.x - n + 1);v.b = min(v.b, v.x);v.l = max(v.l, v.y - m + 1);v.r = min(v.r, v.y);int X = v.x - n + sx, Y = v.y - m + sy; // 高桥当前位置对应原地图的实际坐标// 排除非法情况if(v.x < 0 || v.x > 2 * n || v.y < 0 || v.y > 2 * m) continue;if(X >= v.t && X <= v.b && Y >= v.l && Y <= v.r && mp[X][Y] == '#') // 还在地图内且与垃圾位置重合continue;if(vis[v.t][v.b][v.l][v.r][v.x][v.y] == true)continue;if(s[v.b][v.r] - s[v.b][v.l - 1] - s[v.t - 1][v.r] + s[v.t - 1][v.l - 1] == 0) // 剩余位置无垃圾{cout << v.step;return;}q.push(v);vis[v.t][v.b][v.l][v.r][v.x][v.y] = true;}}cout << -1;
}

F - Not Adjacent

题意

给定一个长度为 \(N\) 的整数序列 \(A=(A _ 1,A _ 2,\ldots,A _ N)\)

明显 \(A\) 存在 \(2 ^ N\) 个子序列(即元素不一定相邻)。

问有多少个子序列满足以下两个条件:

  • 选出来的元素(保留的数字)在原序列 \(A\) 中不相邻。
  • 选出来的数字总和是 \(M\) 的倍数。

只要元素被取出的位置不同,就可以被当作不同的子序列。

思路

考虑爆搜,但 \(N = 60\) 显然行不通。

考虑折半搜索,将序列分为前后两部分,因为本题存在“不能选择相邻元素”的限制,因此在 \(\frac N 2 = 30\) 个数字组成的序列中,最多只能取出 \(15\) 个数字求和。这样每部分能够得到的总和个数实测最多只会到达 \(2 \times 10^6\) 级别。

对于 \([1, \frac N 2]\) 部分,借助深搜求出所有可能的总和(\(\bmod M\) 的结果),然后借助哈希表(unordered_map)存储每种总和出现的次数。

对于 \([\frac N 2+1, N]\) 部分,同样借助深搜求出所有可能的总和(\(\bmod M\) 的结果),然后考虑每个总和与左半部分的值相加,能够得到多少个不同子序列的总和恰好是 \(M\) 的倍数。假设当前得到的总和为 \(S\),那么再左半部分需要再找到总和为 \((M-S)\bmod S\) 的子序列,才可以保证两者相加的值 \(\bmod M = 0\)

但这样还需要注意一个问题,我们需要保证 \(\frac N 2\)\(\frac N 2 + 1\) 这两个数字不能够同时取到。所以在搜索的时候需要额外再处理一个条件,即两部分交界处的这个数字在当前总和当中是否有用到。

对于左半部分,根据该条件把总和分别存在两个不同的哈希表中。

而对于右半部分,如果当前搜索得到的总和未使用到 \(\frac N 2 + 1\) 位置的数,那么就可以把两个哈希表中总和为 \((M-S)\bmod S\) 的子序列都找出来加入答案;而如果当前搜索得到的总和使用到了 \(\frac N 2 + 1\) 位置的数,那么就只能取未使用 \(\frac N 2\) 位置的哈希表中的总和为 \((M-S)\bmod S\) 的子序列。

由于读取的次数较多,因此本题更偏向于使用哈希表 unordered_map 而非红黑树 map

时间复杂度 \(O(D\log D)\),其中 \(D\) 表示从 \(\frac N 2\) 个数中不取相邻元素所能得到的总和情况数。

代码

typedef long long ll;int n, m;
int a[65];
unordered_map<int, int> mp[2]; // mp[0/1] 分别存储 未使用/使用了 a[n/2] 时,在左半部分能够获得的子序列总和以及数量
ll ans = 0;void dfs1(int p, int maxx, int sum, bool useMax)
{if(p > maxx){mp[useMax][sum]++;return;}// 如果选 a[p]dfs1(p + 2, maxx, (sum + a[p]) % m, p == maxx);// 如果不选 a[p]dfs1(p + 1, maxx, sum, 0);
}void dfs2(int p, int minn, int sum, bool useMin)
{if(p < minn){sum = (m - sum) % m; // 需要在左半部分找的数值,使其加上当前 sum 后为 m 的倍数if(useMin) // 当前使用了 a[n/2+1],那么左半部分就不能使用 a[n/2]ans += mp[0][sum];elseans += mp[0][sum] + mp[1][sum];return;}// 如果选 a[p]dfs2(p - 2, minn, (sum + a[p]) % m, p == minn);// 如果不选 a[p]dfs2(p - 1, minn, sum, 0);
}void solve()
{cin >> n >> m;for(int i = 1; i <= n; i++)cin >> a[i];if(n == 1){if(a[1] % m == 0)cout << 2;elsecout << 1;return;}dfs1(1, n / 2, 0, false);dfs2(n, n / 2 + 1, 0, false);cout << ans;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/935160.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

zju博士资格考试考前复习(微分方程方向)ode 部分

人甚至无法共情四年前的自己(这真是人算的东西吗……资料:21-22 / 23-24 ode课程资料 只整理计算部分,现在已经不会计算了。。。 例题一做就是 40min 起步。。。。。。 1. 线性方程 \[u = fu + g \]通解 \[F(t) = \…

测试一下博客功能

一级标题咱也不知道一级标题能不能用二级标题 这里是二级内容 加粗 三级标题 四级标题 二二二 二二二eee ssss System.out.println("HelloWorld");

AI如何改变芯片设计

本文探讨人工智能如何革新芯片设计流程,包括缺陷检测、数字孪生建模、参数优化等应用。AI通过创建替代模型加速设计过程,降低实验成本,同时面临精度不足和数据整合挑战,未来将实现人机协作的芯片设计新模式。AI如何…

NOIP 2024

时隔一年重新做。 T1 因为之前做过的缘故 大概 15min 贪心秒了。都不能换就跳过,相同也跳过。否则诶个检查 \(s_1,s_2\) 可不可以换成功,成功了就跳过不要再多换一次了。 换的过程考虑从 \(i\) 后面开始一直走,直到…

2025/10/11

A 用时:3h 预期:100pts 实际:100pts 考虑枚举 \(x\) 找到绝对众数为 \(x\) 的区间去扩展,注意到如果 \([l,r]\) 的绝对众数为 \(x\),则里面一定有一段形如 \(x,x\) 或 \(x,y,x\),然后随便做,一开始的实现是一大…

好玩热门的switch游戏推荐【PC+安卓】塞尔达传说:王国之泪|v1.4.2整合版|官方中文| 附switch模拟器

好玩热门的switch游戏推荐【PC+安卓】塞尔达传说:王国之泪|v1.4.2整合版|官方中文| 附switch模拟器【PC+安卓】塞尔达传说:王国之泪|v1.4.2整合版|官方中文|解压可玩 附switch模拟器 【新switch模拟器已经正式支持新版…

十年运维工程师总结

四个字总结我的十年运维生涯,高开低走。 第一家公司,规模不小的游戏公司(现很好)。 第二家公司,规模很小的游戏公司(现已死)。 第三家公司,规模很小的游戏公司(现已死)。 第四家公司,规模很小的直播公司(现…

运动控制教学——5分钟学会Dijkstra与A*搜索算法!(附仿真视频及代码) - 教程

运动控制教学——5分钟学会Dijkstra与A*搜索算法!(附仿真视频及代码) - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-f…

ffplay数据结构解析

ffmpeg版本5-1-6 数据结构 FrameQueue typedef struct FrameQueue {Frame queue[FRAME_QUEUE_SIZE];//存储解码后帧数据(视频YUV/RGB、音频PCM、字幕)的预分配内存池int rindex;//指向当前待读取(播放)的帧位置,相…

CNN 发展历程

CNN 发展历程 • LeNet (1998):局部感受野 + 池化,第一次真正提出 CNN • AlexNet (2012):ReLU + Dropout + 数据增强 + GPU,加速深度网络训练 • VGG (2014):33 小卷积堆叠,结构简洁、可扩展 • Inception (201…

FileX和ThreadX精简版

FILEX精简版合并函数级源文件到整个类级源文件原版Filex和Threadx是每个函数一个文件,(我能想到的好处是方便做单元测试,也可能功能安全认证方便点?)这样在windows环境下编译速度会提高一些(编译一个c/cpp文件都…

C 基础教程

C 基础教程C 语言速查与详解目录最小程序与基本语法 基本类型与字面量 变量、常量与作用域 控制流 函数 指针与地址 数组与字符串 结构体、联合与枚举 内存管理 字符与 I/O 宏与预处理器 指针高级用法 错误处理 存储类…

ue4素材场景 - MKT

ue4素材场景https://www.aigei.com/s?q=Brushify+-+Urban+Buildings+Pack环境】工业区环境(Industrial Area Environment)环境】城市建筑包(Brushify - Urban Buildings Pack) 【虚幻模型】- 科幻建筑包 Brush

实用指南:《新能源汽车故障诊断与排除》数字课程资源包开发说明

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

阅读《构建之法》的思考与问题

问题一:软件工程的"复杂性"本质在AI时代是否被真正改变? 关联章节:第1章"软件的特殊性"中关于复杂性的讨论 上下文:复杂性是软件的本质特性之一,不会因工具进步而消失。 支持事例:Linux内核…

实验报告5(链栈基本操作,数制转换,匹配算法,伴舞问题)

一、实验目的: 1.学会进行链栈的基本操作。 2.进行数制的转换,将十进制整数转换为十六进制数。 3.实现的匹配算法。 4.实现舞伴问题。 二、实验仪器或设备: 操作系统:Windows11 编程环境:Dev-cpp 5.11 三、算法总…

阅读和提问作业1:《构建之法》提问

对学校现存教育方式的反馈对学校现存教育方式的反馈:很多老师的教育不讲为什么,就灌输一些死记硬背的知识,学过就忘,也不理解为什么,难以真正应用实践。在学校中碰到的师生关系:一些老师就是为了完成教学任务,学…

Selenium+python自动化1-环境搭建 - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

初四夜间/休息日安排

夜间: 最晚 \(20:30\) 前写完作业 写完作业的时间$ - 21:00$ 做初中数学大题两道(或选择四道,填空三道)、物理题四道,化学题五道 \(21:00-22:00\) 物理竞赛(有时可选做高等数学) \(22:00-22:30\) 背诵文科(语文…

2025年9月22日优雅草蜻蜓I通讯水银版4.1.9版本正式发布-完成所有服务升级版本重构升级-修复大量漏洞-优化启动步骤-卓伊凡|bigniu|麻子|贝贝| - 指南

2025年9月22日优雅草蜻蜓I通讯水银版4.1.9版本正式发布-完成所有服务升级版本重构升级-修复大量漏洞-优化启动步骤-卓伊凡|bigniu|麻子|贝贝| - 指南2025-10-11 22:31 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { wh…