E. Serval and Modulo

news/2025/3/27 13:09:31/文章来源:https://www.cnblogs.com/archer233/p/18789936

Serval and Modulo 题解:模运算 + 因数分解

题目链接


题目分析

Serval 给定了两个数组 $ a $ 和 $ b $,其中 $ b $ 是通过将 $ a $ 中的每个元素对某个魔法数 $ k $ 取模后得到的,并且 $ b $ 被打乱了。我们需要找到一个可能的魔法数 $ k $(满足 $ 1 \leq k \leq 10^9 $),使得 $ b $ 可以由 $ a $ 按照上述规则生成。如果不存在这样的 $ k $,输出 $ -1 $。


思路大意

这道题的核心目标是找到一个合适的 $ k $,使得:

  1. 对于数组 $ a $ 的每个元素 $ a_i $,有 $ a_i \mod k = b_j $,其中 $ b_j $ 是数组 $ b $ 中的一个元素。
  2. 数组 $ b $ 是通过重新排列 $ [a_1 \mod k, a_2 \mod k, \dots, a_n \mod k] $ 得到的。

核心观察

  1. 如果数组 $ a $ 和 $ b $ 完全相同(即排序后相等),那么任意一个大于等于最大值的 $ k $ 都是合法答案。
  2. 如果数组 $ a $ 和 $ b $ 不同,则需要通过模运算找到一个合适的 $ k $。
  3. 关键在于利用 $ \text{sum}(a) - \text{sum}(b) $ 的差值 $ \text{diff} $ 来约束 $ k $ 的可能取值。

数学推导

假设 $ k $ 是一个合法的答案,则对于所有 $ i $,有:

\[a_i \mod k = b_j \]

这意味着 $ a_i - b_j $ 必须是 $ k $ 的倍数。因此,我们可以得出:

\[k \mid (a_i - b_j) \]

进一步地,如果我们对所有 $ i $ 计算 $ a_i - b_j $ 的和 $ \text{diff} = \text{sum}(a) - \text{sum}(b) $,则 $ k $ 必须是 $ \text{diff} $ 的因数。


算法设计

基于上述分析,我们可以设计如下算法:

  1. 输入与初始化:读入数组 $ a $ 和 $ b $,并计算两者的差值 $ \text{diff} = \text{sum}(a) - \text{sum}(b) $。
  2. 排序比较:对数组 $ a $ 和 $ b $ 排序。如果排序后的 $ a $ 和 $ b $ 相同,则直接输出一个较大的 $ k $(如 $ 10^6 + 1 $)。
  3. 检查差值:如果 $ \text{diff} \leq 0 $,则输出 $ -1 $。
  4. 枚举因数:枚举 $ \text{diff} $ 的所有因数 $ k $,并检查是否满足条件:
    • 将数组 $ a $ 中的每个元素对 $ k $ 取模,得到新数组 $ c $。
    • 排序 $ c $ 并与 $ b $ 比较,如果相等,则 $ k $ 是合法答案。
  5. 返回结果:如果找到合法的 $ k $,输出它;否则输出 $ -1 $。

代码详解

以下是完整的代码实现及其详细解释:

#include <bits/stdc++.h>
#define int long long
#define all(x) x.begin(),x.end()
#define rall(x) x.rbegin(),x.rend()
#define pb push_back
#define pii pair<int,int>
using namespace std;
const int mod = 998244353;// 计算 gcd 的函数
int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }// 快速幂函数
int qpw(int a, int b) {int ans = 1;while (b) {if (b & 1) ans = ans * a % mod;a = a * a % mod;b >>= 1;}return ans;
}// 求逆元函数
int inv(int x) { return qpw(x, mod - 2); }void solve() {int n; cin >> n; // 输入数组长度vector<int> a(n), b(n);int dif = 0;// 输入数组 a 并计算 sum(a)for (int i = 0; i < n; i++) {cin >> a[i];dif += a[i];}// 输入数组 b 并计算 sum(b)for (int i = 0; i < n; i++) {cin >> b[i];dif -= b[i];}// 对数组 a 和 b 排序sort(all(a));sort(all(b));// 如果 a 和 b 相同,直接输出一个较大的 kif (a == b) {cout << (int)(1e6 + 1) << '\n';return;}// 如果 diff <= 0,说明找不到合法的 kif (dif <= 0) {cout << -1 << '\n';return;}// 定义 check 函数,验证 k 是否合法auto check = [&](int x) {vector<int> c(n);for (int i = 0; i < n; i++) {c[i] = a[i] % x;}sort(all(c));return c == b;};// 枚举 diff 的因数for (int i = 1; i * i <= dif; i++) {if (dif % i == 0) {if (check(i)) {cout << i << '\n';return;}if (check(dif / i)) {cout << dif / i << '\n';return;}}}// 如果没有找到合法的 k,输出 -1cout << -1 << '\n';
}signed main() {ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr); // 加速输入输出int _ = 1; cin >> _; // 测试用例数量while (_--) solve(); // 处理每个测试用例
}

代码关键部分解析

sort

  • 作用:对数组进行排序。
  • 特性:在本题中,我们使用排序来判断数组 $ a $ 和 $ b $ 是否可以直接匹配。

差值计算

for (int i = 0; i < n; i++) {cin >> a[i];dif += a[i];
}
for (int i = 0; i < n; i++) {cin >> b[i];dif -= b[i];
}
  • 作用:计算数组 $ a $ 和 $ b $ 的差值 $ \text{diff} $。
  • 特性:如果 $ \text{diff} \leq 0 $,则说明找不到合法的 $ k $。

枚举因数

for (int i = 1; i * i <= dif; i++) {if (dif % i == 0) {if (check(i)) {cout << i << '\n';return;}if (check(dif / i)) {cout << dif / i << '\n';return;}}
}
  • 作用:枚举 $ \text{diff} $ 的所有因数,并检查是否满足条件。
  • 特性:通过因数分解减少枚举范围,提高效率。

检查函数

auto check = [&](int x) {vector<int> c(n);for (int i = 0; i < n; i++) {c[i] = a[i] % x;}sort(all(c));return c == b;
};
  • 作用:验证给定的 $ k $ 是否合法。
  • 特性:通过对数组 $ a $ 的每个元素取模并排序,判断是否与数组 $ b $ 相同。

示例分析

输入

5
4
3 5 2 7
0 1 1 1
5
3 1 5 2 4
1 2 3 4 5
6
2 3 4 7 8 9
1 2 3 6 7 8
5
21 22 25 28 20
0 1 2 1 0
6
1 1 2 3 5 8
0 0 1 1 0 0

输出

2
31415926
-1
4
-1

解释

  1. 第一个测试用例

    • $ a = [3, 5, 2, 7] \(,\) b = [0, 1, 1, 1] $。
    • $ \text{diff} = 17 - 2 = 15 $。
    • 枚举 $ \text{diff} $ 的因数 $ 1, 3, 5, 15 $,发现 $ k = 2 $ 合法。
    • 输出 $ 2 $。
  2. 第二个测试用例

    • $ a = [3, 1, 5, 2, 4] \(,\) b = [1, 2, 3, 4, 5] $。
    • $ \text{diff} = 15 - 15 = 0 $。
    • 输出 $ 31415926 $(任意一个大于等于最大值的 $ k $)。
  3. 第三个测试用例

    • $ a = [2, 3, 4, 7, 8, 9] \(,\) b = [1, 2, 3, 6, 7, 8] $。
    • 无法找到合法的 $ k $。
    • 输出 $ -1 $。

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

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

相关文章

Gitee DevOps 实践指南:本土团队效率提升的新范式

在数字化转型的浪潮中,Gitee DevOps 作为国内领先的一体化研发效能平台,通过深度融合代码托管、CI/CD、项目管理等核心功能,为企业提供了本土化的 DevOps 解决方案。一、Gitee DevOps 的核心价值定位 在数字化转型的浪潮中,Gitee DevOps 作为国内领先的一体化研发效能平台,…

那些正常的动态规划

目录前言动态规划到底是啥?线性dp最长上升子序列子集和子序列和子串的区别内容分析最大上升子序列例题1——[NOIP2004 提高组] 合唱队形分析最长公共子序列最长公共子串平面dp例题2——[NOIP2000 提高组] 方格取数分析例题3——[NOIP2008 提高组] 传纸条分析例题4——最大加权…

3月24日刷题笔记-第六章 流量特征分析-常见攻击事件 tomcat

1、在web服务器上发现的可疑活动,流量分析会显示很多请求,这表明存在恶意的扫描行为,通过分析扫描的行为后提交攻击者IP flag格式:flag{ip},如:flag 我们查看流量包,可以发现有一个外部IP在对常见端口进行SYN扫描,判断出为恶意IPflag{14.0.0.120} 2、找到攻击者IP后请通过…

如何在云效中使用 DeepSeek 等大模型实现 AI 智能评审

除了代码智能补全外,AI 代码智能评审是 DevOps 领域受开发者广泛关注的另一场景了。本文,我们将结合云效代码管理 Codeup、流水线 Flow 和 DeepSeek,分享一种企业可快速自主接入,即可实现的 AI 智能评审解决方案,希望给大家一些启发。作者:崔力强、黄博文 除了代码智能补…

T+0量化:JAVA接入Level2高频行情(附Python代码)

去年在知乎分享过一个网格策略,评论区全是"代码能跑通但实盘不敢用"的留言。当时我也一样——用第三方平台回测美滋滋,一到实盘就怂:行情延迟3秒、API调用次数受限、策略逻辑被平台规则卡脖子…直到把整套系统搬回本地,才发现自建交易系统的快感就像从合租屋搬进…

制作一个简单的带有3D打印部件的四足蜘蛛机器人

在这个项目中,我将向您展示如何使用3D打印部件制作一个简单的4腿行走蜘蛛机器人。该设计主要由上下板、臂接插件、腿和伺服支架五个部分组成。机器人的4条腿由4个手臂部分和4个腿部分组成。机器人的运动总共使用了8个业余伺服电机,4个在手臂上,4个在腿上。在电路方面,首选E…

统计学习之数据挖掘(结构数据)

统计学习之数据挖掘(结构数据):降维聚类关联度分析分类神经网络

2024 腾讯游戏安全大赛 mobile 初赛 wp

找关键结构体 https://www.cnblogs.com/revercc/p/17641855.html 找GWORLD https://bbs.kanxue.com/thread-280042.htm可以发现是 TEXT包裹的,utf-16编码,ida alt + b搜索 53 00 65 00 61 00 6D 00 6C 00 65 00 73 00 73 00 54 00 72 00即可网上翻即可找到 GWorld对应地址: 0…

制造业订单处理烦恼多,日事清 OTD 管理为您排忧解难

你是不是经常因为接单和交货时间差太大而焦头烂额?今天我们就结合制造业OTD管理,带您了解如何应用日事清进行订单交付全周期管理。日事清可以帮你设定精细的流程,从接单到发货,清晰可控地帮你解决以上烦心事。在制造业里打拼,每天都得面对各种烦心事,比如订单处理慢、生产…

如何在SSD1306上显示动态表情符号位图

解锁您的SSD1306上充满活力的视觉效果!学习毫不费力地显示动态表情符号位图,并以风格增强您的项目。 在本教程中,我们将通过使用PCBX在线模拟环境在SSD1306 OLED显示器上显示位图图像的过程。本教程将介绍设置PCBX模拟,格式化位图数据,配置显示大小和管理图像延迟。步骤1:…

redis基础数据结构——ZipList

ZipList 基于特殊写法实现的双端链表,由一系列特殊编码的连续内存块组成,可以像deque一样在双端压入/弹出,并且时间复杂度在O(1) 整体ZL结构如下zlbytes(uint32):当前zl总的byte数。 zltail(uint32):尾结点的offset,指向的是最后一个entry的起始地址。 zllen(uint16):记…