惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

N
Netflix TechBlog - Medium
V
Vulnerabilities – Threatpost
Google Online Security Blog
Google Online Security Blog
Hugging Face - Blog
Hugging Face - Blog
L
LINUX DO - 热门话题
云风的 BLOG
云风的 BLOG
P
Proofpoint News Feed
D
Docker
C
Cyber Attacks, Cyber Crime and Cyber Security
MyScale Blog
MyScale Blog
P
Palo Alto Networks Blog
T
Tenable Blog
P
Privacy International News Feed
Google DeepMind News
Google DeepMind News
小众软件
小众软件
Cisco Talos Blog
Cisco Talos Blog
aimingoo的专栏
aimingoo的专栏
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
A
Arctic Wolf
C
Cybersecurity and Infrastructure Security Agency CISA
C
Cisco Blogs
T
Threat Research - Cisco Blogs
NISL@THU
NISL@THU
The Hacker News
The Hacker News
Project Zero
Project Zero
AWS News Blog
AWS News Blog
Simon Willison's Weblog
Simon Willison's Weblog
cs.CL updates on arXiv.org
cs.CL updates on arXiv.org
T
Threatpost
V
Visual Studio Blog
The GitHub Blog
The GitHub Blog
The Cloudflare Blog
Last Week in AI
Last Week in AI
Jina AI
Jina AI
Cyberwarzone
Cyberwarzone
The Register - Security
The Register - Security
C
CXSECURITY Database RSS Feed - CXSecurity.com
Vercel News
Vercel News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
MongoDB | Blog
MongoDB | Blog
U
Unit 42
Scott Helme
Scott Helme
A
About on SuperTechFans
WordPress大学
WordPress大学
F
Fortinet All Blogs
大猫的无限游戏
大猫的无限游戏
G
GRAHAM CLULEY
Latest news
Latest news
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Schneier on Security

OneCoder

【GESP】C++二级真题 luogu-B4553 [GESP202606 二级] 完全平方数计数 【GESP】C++一级真题 luogu-B4551 [GESP202606 一级] 去旅行 【GESP】C++一级真题 luogu-B4552 [GESP202606 一级] 交税 【NOIP】2000真题解析 luogu-P1023 税收与补贴问题(适合GESP四、五级以上练习) 【NOIP】2000真题解析 luogu-P1022 计算器的改良(适合GESP四、五级以上练习) 【NOIP】2001真题解析 luogu-P1029 最大公约数和最小公倍数问题 【CSP】CSP-X 2018真题 11的倍数 luogu-B4075 (适合GESP三级及以上考生练习) 【CSP】CSP-X 2018真题 统计成绩 luogu-B4074 (适合GESP二级及以上考生练习) 【CSP】CSP-X 2018真题 快递费用 luogu-B4073 (适合GESP二级及以上考生练习) 【CSP】CSP-X 2018真题 小明的照片 luogu-B4072 (适合GESP一级及以上考生练习) 【GESP】C++四级练习 luogu-P1138 第 k 小整数 【NOIP】2008真题解析 luogu-P1125 笨小猴 【信奥业余科普】C++ 的奇妙之旅 29:别让 TLE 和 MLE 偷走你的分——复杂度估算与数据范围速查 【信奥业余科普】C++ 的奇妙之旅 28:规范比赛代码的钥匙——文件操作与输入输出重定向(freopen) 【CSP】CSP-J 2023真题 公路 luogu-P9749 (适合GESP四级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 27:高效处理数据的利器——常用算法库(algorithm) 【信奥业余科普】C++ 的奇妙之旅 26:高效的键值对——映射(map)与多重映射(multimap) 【CSP】CSP-J 2022真题 乘方 luogu-P8813 (适合GESP二级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 25:自动排序的利器——集合(set)与多重集合(multiset) 【CSP】CSP-J 2019真题 纪念品 luogu-P5662 (适合GESP六级及以上考生练习) 【信奥业余科普】C++ 的奇妙之旅 24:拆解 deque——分段连续的双端队列 【信奥业余科普】C++ 的奇妙之旅 23:主动限制的艺术——栈(stack)与队列(queue)
【CSP】CSP-J 2022真题 解密 luogu-P8814 (适合GESP四级及以上考生练习)
OneCoder · 2026-05-31 · via OneCoder

CSP-J 2022真题-解密,是一道结合数学推导与数值运算的经典题目。本题可以通过将方程组转化为一元二次方程,利用求根公式在 $O(1)$ 的时间内求解;也可以利用单调性通过二分法进行求解。适合 GESP 四级及以上考生练习,难度⭐⭐,洛谷难度等级普及-

P8814 [CSP-J 2022] 解密

题目要求

题目描述

给定一个正整数 $k$,有 $k$ 次询问,每次给定三个正整数 $n_i, e_i, d_i$,求两个正整数 $p_i, q_i$,使 $n_i = p_i \times q_i$、$e_i \times d_i = (p_i - 1)(q_i - 1) + 1$。

输入格式

第一行一个正整数 $k$,表示有 $k$ 次询问。

接下来 $k$ 行,第 $i$ 行三个正整数 $n_i, d_i, e_i$。

输出格式

输出 $k$ 行,每行两个正整数 $p_i, q_i$ 表示答案。

为使输出统一,你应当保证 $p_i \leq q_i$。

如果无解,请输出 NO

输入输出样例 #1

输入 #1

1
2
3
4
5
6
7
8
9
10
11
10
770 77 5
633 1 211
545 1 499
683 3 227
858 3 257
723 37 13
572 26 11
867 17 17
829 3 263
528 4 109

输出 #1

1
2
3
4
5
6
7
8
9
10
2 385
NO
NO
NO
11 78
3 241
2 286
NO
NO
6 88

说明/提示

【数据范围与约定】

以下记 $m = n - e \times d + 2$。

保证对于 $100\%$ 的数据,$1 \leq k \leq {10}^5$,对于任意的 $1 \leq i \leq k$,$1 \leq n_i \leq {10}^{18}$,$1 \leq e_i \times d_i \leq {10}^{18}$,$1 \leq m \leq {10}^9$。

测试点编号$k \leq$$n \leq$$m \leq$特殊性质
$1$$10^3$$10^3$$10^3$保证有解
$2$$10^3$$10^3$$10^3$
$3$$10^3$$10^9$$6\times 10^4$保证有解
$4$$10^3$$10^9$$6\times 10^4$
$5$$10^3$$10^9$$10^9$保证有解
$6$$10^3$$10^9$$10^9$
$7$$10^5$$10^{18}$$10^9$保证若有解则 $p=q$
$8$$10^5$$10^{18}$$10^9$保证有解
$9$$10^5$$10^{18}$$10^9$
$10$$10^5$$10^{18}$$10^9$

题目分析

本题给出了包含两个未知数 $p$ 和 $q$ 的方程组,要求我们根据已知的 $n, e, d$ 求解符合条件的 $p$ 和 $q$。由于数据范围中 $k \le 10^5$,如果使用暴力枚举因数的方式求解,时间复杂度会达到 $O(k \sqrt{n})$,显然会超时。因此我们需要更高效的求解方法。

1. 代数变形与方程组构建

首先,我们对方程组进行展开与化简。

已知方程组为:

\[\begin{cases} n = p \times q & \text{①} \\ e \times d = (p - 1)(q - 1) + 1 & \text{②} \end{cases}\]

展开方程 ②:

\[e \times d = p \times q - p - q + 1 + 1\] \[e \times d = p \times q - (p + q) + 2\]

将方程 ① 中的 $n = p \times q$ 代入上式:

\[e \times d = n - (p + q) + 2\]

变形可得 $p + q$ 的表达式:

\[p + q = n - e \times d + 2\]

为了书写简便,我们令 $m = p + q = n - e \times d + 2$。结合题目已有的方程,我们可以构建一个新的方程组:

\[\begin{cases} p + q = m \\ p \times q = n \end{cases}\]

这变成了经典的“已知两数之和与两数之积,求解这两数”的问题。


2. 解法一:一元二次方程求根公式(推荐)

根据韦达定理,$p$ 和 $q$ 可以看作是关于 $x$ 的一元二次方程的两个实数根:

\[x^2 - m x + n = 0\]

利用求根公式,可得:

\[x = \frac{m \pm \sqrt{m^2 - 4n}}{2}\]

因为题目要求 $p \le q$,所以:

\[p = \frac{m - \sqrt{m^2 - 4n}}{2},\quad q = \frac{m + \sqrt{m^2 - 4n}}{2}\]

求解时的判定与注意事项:
  1. 无实数解判定: 若判别式 $\Delta = m^2 - 4n < 0$,方程无实数解,输出 NO
  2. 整数解判定
    • 判别式 $\Delta$ 必须是完全平方数。我们可以计算 $r = \lfloor \sqrt{\Delta} \rfloor$(或使用四舍五入 round(sqrt(delta))),并校验是否满足 $r \times r == \Delta$。如果不满足,说明 $\sqrt{\Delta}$ 不是整数,即无整数解。
    • 分子 $m - r$ 和 $m + r$ 必须是偶数,即满足 $(m - r) \pmod 2 == 0$。如果不能整除,也说明无整数解。
  3. 数据溢出预防: 虽然提示中 $m \le 10^9$,但 $m^2$ 的范围可达 $10^{18}$,$n$ 的范围可达 $10^{18}$。在 C++ 中,我们必须使用 long long 类型来承载所有的计算,以防止数值溢出。

该方法单次查询的时间复杂度为 $O(1)$,总时间复杂度为 $O(k)$,执行效率非常高。


3. 解法二:二分答案法

如果不想使用浮点数开方函数 sqrt(),也可以利用单调性采用二分查找。

由于 $p + q = m$,且 $p \le q$,我们可以确定 $p$ 的取值范围在 $[1, \lfloor m / 2 \rfloor]$ 之间。

在这段区间内,随着 $p$ 的增大,乘积 $p \times (m - p)$ 是严格单调递增的。 因此,我们可以在 $[1, m/2]$ 内二分查找 $p$:

  • 设当前二分区间的中点为 mid,计算乘积 val = mid * (m - mid)
  • val == n,说明找到了符合条件的整数解,此时 $p = \mathrm{mid}$,$q = m - \mathrm{mid}$。
  • val < n,说明当前的 mid 偏小,应向右半区间继续查找,令 L = mid + 1
  • val > n,说明当前的 mid 偏大,应向左半区间继续查找,令 R = mid - 1

二分查找每次询问的时间复杂度为 $O(\log m)$,总时间复杂度为 $O(k \log m)$。在 $k = 10^5, m = 10^9$ 的情况下,总计算次数约为 $3 \times 10^6$ 次,完全可以在时限内通过。


示例代码

方法一:求根公式法($O(1)$)

以下是使用一元二次方程求根公式实现的 C++ 代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <cmath>

void solve() {
    long long n, d, e;
    std::cin >> n >> d >> e;

    // 根据推导,m = p + q
    long long m = n - e * d + 2;

    // 计算判别式 delta = m^2 - 4n
    long long delta = m * m - 4 * n;

    // 如果判别式小于 0,无实数解
    if (delta < 0) {
        std::cout << "NO\n";
        return;
    }

    // 对方程求根,并校验是否为完全平方数
    long long r = std::round(std::sqrt(delta));
    if (r * r != delta) {
        std::cout << "NO\n";
        return;
    }

    // 校验分子是否为偶数,即是否能被 2 整除
    if ((m - r) % 2 != 0) {
        std::cout << "NO\n";
        return;
    }

    // 计算 p 和 q
    long long p = (m - r) / 2;
    long long q = (m + r) / 2;

    // 校验 p 和 q 是否为正整数
    if (p <= 0 || q <= 0) {
        std::cout << "NO\n";
        return;
    }

    std::cout << p << " " << q << "\n";
}

int main() {
    // 优化输入输出流性能
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int k;
    std::cin >> k;
    while (k--) {
        solve();
    }

    return 0;
}

方法二:二分答案法($O(\log m)$)

以下是使用二分查找实现的 C++ 代码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <iostream>

void solve() {
    long long n, d, e;
    std::cin >> n >> d >> e;

    // 根据推导,m = p + q
    long long m = n - e * d + 2;

    // 二分区间 p <= q,且 p + q = m,因此 p 必然在 [1, m / 2]
    long long L = 1, R = m / 2;
    long long p = -1;

    while (L <= R) {
        long long mid = L + (R - L) / 2;
        long long val = mid * (m - mid);

        if (val == n) {
            p = mid;
            break; // 找到答案,退出二分
        } else if (val < n) {
            L = mid + 1; // 乘积偏小,增大 p
        } else {
            R = mid - 1; // 乘积偏大,减小 p
        }
    }

    // 如果没有找到解
    if (p == -1) {
        std::cout << "NO\n";
    } else {
        long long q = m - p;
        std::cout << p << " " << q << "\n";
    }
}

int main() {
    // 优化输入输出流性能
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int k;
    std::cin >> k;
    while (k--) {
        solve();
    }

    return 0;
}


结语

本题的核心突破口在于对方程组的展开和化简。通过代数变形,将复杂的乘积方程转化为了已知和与积的经典二次方程 model。在实战中,熟练掌握这类代数变形技巧以及边界和精度的合理校验,是快速且准确地解决数学类算法题目的关键。

所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code

GESP 学习专题站:GESP WIKI

"luogu-"系列题目可在洛谷题库进行在线评测。

"bcqm-"系列题目可在编程启蒙题库进行在线评测。

欢迎加入Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答

欢迎加入C++ GESP/CSP认证学习QQ频道,考试资源总结汇总

欢迎加入C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号

GESP/CSP 认证学习微信公众号