5 ABC413 题解

news/2025/10/10 21:14:48/文章来源:https://www.cnblogs.com/michaele/p/19133898

ABC 413 题解

D

题面

给定一个长度为 \(N\) 的整数序列 \(A=(A_1,A_2,\ldots,A_N)\)

保证对于任何 \(i\ (1\le i\le N)\)\(A_i\) 不为 \(0\)

判断是否存在 \(A\) 的一个排列 \(B=(B_1,B_2,\ldots,B_N)\) 使得 \(B\) 形成一个等比数列。

如果存在一个实数 \(r\) 使得 \(S_{i+1}=rS_i\) 对于所有整数 \(1\le i\lt N\) 都成立,那么序列 \(S=(S_1,S_2,\ldots,S_N)\) 就是一个等比数列。

\(-10^9 \le A_i \le 10^9 ,\ 1 \le N \le 2 \times 10^5\)

题解

我一开始的思路是先将整个数组按照绝对值大小排序,然后算出 \(a_1 / a_2\) 的值,也就是题目中的 \(r\) ,然后从第二个开始,向后依次算出 \(a_2 / a_3,a_3 / a_4, \cdots\) ,比较他们和 \(r\) 的关系,然后判断是否是一个等比数列,但这样做有两个问题

  • 浮点数精度损失,不能够保证正确性
  • 可能会出现绝对值相等的情况,也就是说应该是 \(-+-\) 的情况,结果排序过后变成了 \(--+\)

所以我们分别处理这两个问题

  • 浮点数有精度损失,我们就将浮点数运算转化为整数运算,因为满足条件的额序列呈等比数列,也就是 \(x,rx,r^2x,r^3x\) 所以我们可以对于 \(3 \le i \le n\) 的每一项 \(a_i\) 验证它是否和前面两项构成等比数列,也就是验证 \(a_{i - 2}a_{i} = a_{i - 1}^2\)
  • 我们对每种情况进行分类讨论,然后将他们按照每种情况排列在原数组中,然后利用上面的方法验证

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>
#include <cmath>
#include <vector>using namespace std;namespace michaele {typedef long long ll;typedef __int128 i8;const int N = 2e5 + 10;const double eps = 1e-10;int T, n;int a[N];bool cmp (int a, int b) {return abs (a) < abs (b);}void solve () {vector <int> v0, v1;int cnt0 = 0, cnt1 = 0;cin >> n;for (int i = 1; i <= n; i++) {cin >> a[i];if (a[i] < 0) cnt0++, v0.push_back (a[i]);else cnt1++, v1.push_back (a[i]);}if (cnt0 && cnt1) {if (abs (cnt0 - cnt1) >= 2) {printf ("No\n");return;}}sort (v0.begin(), v0.end(), cmp);sort (v1.begin(), v1.end(), cmp);bool fn = 1, ans = 0;//对每种情况进行讨论,排列在原数组中,然后进行验证if (cnt0 == 0 || cnt1 == 0) {fn = 1;sort (a + 1, a + 1 + n, cmp);for (int i = 3; i <= n; i++) {if ((ll)a[i - 2] * a[i] != (ll) a[i - 1] * a[i - 1]) {fn = 0;break;}}ans |= fn;} else if (cnt0 == cnt1) {fn = 1;int p0 = 0, p1 = 0;for (int i = 1; i <= n; i += 2) {a[i] = v0[p0++];a[i + 1] = v1[p1++];}for (int i = 3; i <= n; i++) {if ((ll)a[i - 2] * a[i] != (ll) a[i - 1] * a[i - 1]) {fn = 0;break;}}ans |= fn;fn = 1;p0 = 0, p1 = 0;for (int i = 1; i <= n; i += 2) {a[i + 1] = v0[p0++];a[i] = v1[p1++];}for (int i = 3; i <= n; i++) {if ((ll)a[i - 2] * a[i] != (ll) a[i - 1] * a[i - 1]) {fn = 0;break;}}ans |= fn;} else if (cnt0 > cnt1) {fn = 1;int p0 = 0, p1 = 0;for (int i = 1; i <= n; i += 2) {a[i] = v0[p0++];}for (int i = 2; i <= n; i += 2) {a[i] = v1[p1++];}for (int i = 3; i <= n; i++) {if ((ll)a[i - 2] * a[i] != (ll) a[i - 1] * a[i - 1]) {fn = 0;break;}}ans |= fn;} else {fn = 1;int p0 = 0, p1 = 0;for (int i = 1; i <= n; i += 2) {a[i] = v1[p1++];}for (int i = 2; i <= n; i += 2) {a[i] = v0[p0++];}for (int i = 3; i <= n; i++) {if ((ll)a[i - 2] * a[i] != (ll) a[i - 1] * a[i - 1]) {fn = 0;break;}}ans |= fn;}if (ans) printf ("Yes\n");else printf ("No\n");}void main () {cin >> T;while (T--) {solve ();}}
}int main () {michaele :: main ();return 0;
}

E

题面

给定一个长度为 \(2^n\) 的排列,编号为 \(0 \sim 2^n - 1\) ,我们可以进行如下操作若干次

  • 选定一个起点编号为 \(a \times 2^b\) ,终点编号为 \((a + 1) \times 2^b - 1\) 的区间,然后将区间内的数翻转(\(reverse\)),\(a,b\) 都为非负整数

求任意次操作后字典序最小的排列

\(1 \le n \le 18\)

题解

image-20250707084336271

可以发现,题目要求的就是我们对上面这些区间进行 \(reverse\) 或不操作,最后得到的字典序最小

对于同一层的每个区间,我们发现它们是独立的,也就是他们的元素不发生交换

也就是说对于一个大区间,我们可以分别找到小区间的最优解,然后合并两个小区间,得到大区间的最优解

考虑两个小区间字典序最小的排列分别为 \(a_0, a_1,\cdots\)\(b_0,b_1,\cdots\)

  • 如果 \(a_0 < b_0\) 那么现在的状态合并起来就还是大区间的最优解
  • 如果 \(a0 > b_0\) 那么显然将 \(b_0\) 放在前面, \(a_0\) 放在后面更优,但是又不能直接 \(reverse\) ,所以我们可以反悔一下之前的所有操作,将两个小区间变成 \(\cdots,a_1,a_0\)\(\cdots, b_1,b_0\) ,然后再 \(reverse\) ,这样就实现了 \(b_0\) 在前面 \(a_0\) 在后面的操作

所以我们从小到大考虑每个区间,将区间分成左右两个区间,比较左右两个区间的第一个元素,看是否需要交换两个区间,这样就得到了最后的最小字典序

时间复杂度 \(O(n\log n)\)

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>using namespace std;namespace michaele {const int N = (1 << 18) + 7;int T, n;int a[N];void solve (int l, int r) {if (l == r) return;int mid = l + r >> 1;solve (l, mid), solve (mid + 1, r);if (a[l] > a[mid + 1]) {for (int i = l; i <= mid; i++) {swap (a[i], a[mid + i - l + 1]);}}return;}void main () {cin >> T;while (T--) {cin >> n;for (int i = 0; i < (1 << n); i++) scanf ("%d", &a[i]);solve (0, (1 << n) - 1);for (int i = 0; i < (1 << n); i++) printf ("%d ", a[i]);printf ("\n");}}
}int main () {michaele :: main ();return 0;
}

F

题面

有一个 \(H \times W\) 网格。让 \((i,j)\) 表示从上往下第 \(i\) 行,从左往上第 \(j\) 列的单元格。其中, \(K\) 个单元格是目标。目标 \((1 \leq i \leq K)\) 的第 \(i\) 个单元格是 \((R_i, C_i)\)

小L 和 小Y 对一个棋子。反复执行以下一系列操作,直到棋子到达目标单元格:

  • 小Y 禁止小L 选择四个方向中的一个。
  • 然后,小L 在 剩下的四个方向中选择一个方向移动棋子,如果棋子的下一步超出网格边界,则不进行移动

小L 的目标是用尽可能少的步数到达目标点。小Y 的目标是阻止棋子到达目标;如果这不可能,她的目标就是最大限度地增加棋子到达目标的步数。

对于满足 \(1 \leq i \leq H,1 \leq j \leq W\) 的所有点 \((i,j)\) ,求解下面的问题并找出所有解的和:

开始下棋时,棋子位于 \((i,j)\) 小格。假设两位棋手都朝着各自的目标采取最优行动。如果 小L 能够使棋子到达目标,那么解就是最少的步数;否则,解就是 \(0\)

\(2 \le H,W \le 3000, 1 \le K \le min (HW, 3000)\)

题解

这道题不同于普通的搜索题,他的核心在于 小Y 会禁掉 小L 的最优决策

image-20250707091004048

\(dis(x,y)\) 表示 \((x, y)\) 到达目标点的最小步数

考虑上图中的蓝色块,假设它由周围的红色块转移过来,那么它一定是被红色点中的次小值更新,而不是最小值,因为 小Y 会禁掉最小值的路径

所以也就相当于我们以所有目标点为起点,去更新其他点,并且我们只在这个点被第二次访问的时候更新它,并放入队列,其实相当于我们求了一条从多个起点到每个点的次短路,我们可以记录一个 \(vis\) 数组表示这个点被访问了多少次,那么我们只会在 \(vis[x] = 2\) 的时候更新它的 \(dis\) 并放入队列

时间复杂度 \(O(nm)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>using namespace std;namespace michaele {typedef long long ll;const int N = 3e3 + 10;int n, m, k;int vis[N][N], dis[N][N];int dx[] = {-1, 1, 0, 0};int dy[] = {0, 0, 1, -1};ll sum = 0;void bfs () {memset (dis, 0x3f, sizeof dis);queue <pair <int, int> > q;for (int i = 1; i <= k; i++) {int x, y;cin >> x >> y;q.push ({x, y});dis[x][y] = 0;vis[x][y] = 1;}while (q.size ()) {int x = q.front ().first;int y = q.front ().second;q.pop ();for (int i = 0; i < 4; i++) {int tx = x + dx[i];int ty = y + dy[i];if (tx < 1 || tx > n || ty < 1 || ty > m) continue;if (!dis[tx][ty]) continue;vis[tx][ty]++;if (vis[tx][ty] == 2) {dis[tx][ty] = dis[x][y] + 1;q.push ({tx, ty});}}}for (int i = 1; i <= n; i++) {for (int j = 1; j <= m; j++) {sum += (dis[i][j] == 0x3f3f3f3f ? 0 : dis[i][j]);// printf ("%d  %d  %d\n", i, j, dis[i][j]);}}cout << sum << endl;}void main () {cin >> n >> m >> k;bfs ();}
}int main () {michaele :: main ();return 0;
}

G

题面

给定一个 \(n \times m\) 的矩阵,以及 \(k\) 个障碍的坐标 \(r_i,c_i\) ,问从左上角能否走到右下角?

每次移动只能向上下左右四个方向移动

\(1 \le n, m \le 2 \times 10^5, 0 \le k \le 2 \times 10^5\)

题解

因为这道题的 \(n, m\) 巨大,所以我们无法用正常的搜索去解决这道题,只能换个角度去考虑

如果我们无法从左上角走到右下角,那么障碍一定是形如下图的

也就是说障碍一定是联通上右和左下边界的,所以我们可以维护一个并查集,然后将联通的两个点合并,注意这里是八联通

然后对左下的点所在的并查集打个 \(tag\) ,再枚举右上边界的障碍所在的并查集,看是否有 \(tag\) 即可

时间复杂度 \(O(k\log k)\)

code

#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>using namespace std;namespace michaele {typedef long long ll;const int N = 2e5 + 10;int n, m, k;int fa[N], tag[N];map <pair <int, int>, int> mp;pair <int, int> a[N];int dx[] = {-1, 1, 0, 0, -1, -1, 1, 1};int dy[] = {0, 0, 1, -1, 1, -1, 1, -1};int fin (int x) {return fa[x] == x ? x : fa[x] = fin (fa[x]);}void merge (int x, int y) {x = fin (x);y = fin (y);if (x == y) return;fa[x] = y;}void main () {cin >> n >> m >> k;int x, y;for (int i = 1; i <= k; i++) {scanf ("%d%d", &x, &y);mp[{x, y}] = i;a[i] = {x, y};}for (int i = 1; i <= k; i++) fa[i] = i;for (int i = 1; i <= k; i++) {x = a[i].first, y = a[i].second;for (int j = 0; j < 8; j++) {int tx = x + dx[j], ty = y + dy[j];if (mp.count ({tx, ty})) {merge (i, mp[{tx, ty}]);}}}for (int i = 1; i <= k; i++) {x = a[i].first, y = a[i].second;if (x == n || y == 1) {tag[fin (mp[{x, y}])] = 1;}}bool fn = 0;for (int i = 1; i <= k; i++) {x = a[i].first, y = a[i].second;if (x == 1 || y == m) {if (tag[fin (mp[{x, y}])]) {fn = 1;break;}}}if (fn) printf ("No\n");else printf ("Yes\n");}
}int main () {michaele :: main ();return 0;
}

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

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

相关文章

4 CF 1032 div3 题解

31 CF 1032 div3 题解 C 题面 给你一个行数为 \(n\) 列数为 \(m\) 的整数矩阵。在第 \(i\) 行和第 \(j\) 列的交叉处的单元格中包含数字 \(a_{ij}\) 。 您可以执行以下操作次:选择两个数字 \(1 \leq r \leq n\) 和 \(…

3 ABC411 C ~ E题解

ABC411 C~E 题解 又是赤石的一天 C 有个长度为 \(N\) 的序列,初始序列中每个数为0 每次操作给定 \(pos\) ,将 pos^1 ,然后输出序列中有多少段不连续的 1 用小样例模拟一下可得,设当前颜色为 \(b\) ,左边颜色为 \(…

9 ABC408 D~F 题解

ABC408 D~F 题解 D 题面 给定一个长度为 \(n\) 的由 01 组成的字符串 \(S\),每次操作可以将某个 0 改成 1,或者将某个 1 改成 0 。 求字符串中至多有一个连续 1 串的最小操作次数。 题解 解法1 考场思路,将每个连续…

8 ABC425 G 题解

ABC425 G 题面 给定两个正整数 \(N,M\) 以及一个长度为 \(N\) 的非负整数序列 \(A = A_1, A_2, ..., A_N\)。求 \[\sum_{x = 0}^{M - 1} \min_{1 \le i \le N} (x \oplus A_i) \]\(1 \le N \le 2 \times 10^5\) \(1 \l…

智能防御,安全赋能:AI-FOCUS 滤海AI DLP 化解外部 AI 风险

在“员工把数据投喂给第三方AI”的常见场景下,企业需要一款可在输入与上传瞬时介入的产品。AI-FOCUS 滤海AI DLP 以流式网关为核心,在用户向大模型输入文本与提交文件/图片时进行敏感数据识别,按风险等级执行放行、…

VS code 中代码补全 自动补全函数括号

使用vscode的pylance插件补全python代码的时候无法补全函数的括号 需要在settings.json中添加这一行即可

学习ReAct并使用langgraph实现一个简单的ReAct AI Agent!!

ReAct介绍 要介绍ReAct最好要知道它是从哪来的。 ReAct这个概念出自《REACT : SYNERGIZING REASONING AND ACTING IN LANGUAGE MODELS》这篇很牛的论文。 论文地址:https://arxiv.org/abs/2210.03629 我们先来看下这篇…

23种设计模式之【策略模式】-核心原理与 Java 实践 - 详解

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

abc 408 d~f

这次做了一次 abc,d 做出来了,但是比较麻烦,又用正确方法写了一遍,整理一下 d,e,f,g 有一些超纲。 abc408d 考虑把区间 \(l,r\) 最后变成 1,然后尝试去表示这个时候的答案。 \(sum[i]\) 表示 \(i\) 位置以及之前…

RMQ与LCA学习笔记

在开始之前先提一下RMQ与LCA这两个东西有什么关系 对于一个序列,对它构建出一颗笛卡尔树之后,两个点的LCA就是原序列中这两个点之间的最大值/最小值(取决于建树时的比较方式) 而对于一棵树,求出来他的欧拉序之后,…

the charm of Chinese language

The charm of Chinese language is you use it to read books. when I can read the original books translation as Chinese. I found the original one lets people dizzy, maybe it needs some graphs to make the …

mamba-硬件感知算法

扫描操作由于A B C这些矩阵现在是动态的了,因此无法使用卷积表示来计算它们(卷积核是固定的),因此,我们只能使用循环表示,如此也就而失去了卷积提供的并行训练能力 Mamba通过并行扫描(parallel scan)算法使得最终并…

完整教程:lua代码解析1

完整教程:lua代码解析1pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", &qu…

system表空间丢失部分文件恢复---惜分飞

system表空间丢失部分文件恢复---惜分飞联系:手机/微信(+86 17813235971) QQ(107644445) 标题:system表空间丢失部分文件恢复 作者:惜分飞©版权所有[未经本人同意,不得以任何形式转载,否则有进一步追究法律责任…

二维数点

介绍 给出一个二维平面內的若干个点,多次询问某个矩形区域內包含多少个点(边界也算)。又或者,给一个长为 n nn 的序列,多次询问区间 [ l , r ] [l,r][l,r] 中值在 [ x , y ] [x,y][x,y] 内的元素个数。 例题 P190…

gitee和github如何修改仓库名并且保持与原远程仓库的连接?(手把手教学) - 实践

gitee和github如何修改仓库名并且保持与原远程仓库的连接?(手把手教学) - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font…

2025.10.10总结 - A

今天上了节英语,感觉还可以,下雨了,一直在宿舍,感觉很爽。

[20251010]建立完善tpt的prr.sql脚本.txt

[20251010]建立完善tpt的prr.sql脚本.txt--//昨天在测试时不小心输入pr命令时多输入一个r,没想到居然执行了,说明在本目录或者SQLPATH环境目录下存在prr.sql脚本。--//当时忙着处理其他事情,先把这件事情放一放,今…

第十一篇

今天是10月10号,今天只上了一节英语课,学习了新的单词,颇有收获。

[Flutter] Flutter APK构建签名并推广到Github workflow

[Flutter] Flutter APK构建签名并推广到Github workflowFlutter APK构建签名并推广到Github workflow 最近在开发flutter软件的时候发现构建出来的apk在手机上不能直接覆盖更新,会提示签名不一致,但由于我的软件是在…