P8814 [CSP-J 2022] 解密 题解

前置知识

整式的加减乘除 —— 初一

思路

看到题目先下意识进行化简 e d ed ed

e d = ( p − 1 ) ( q − 1 ) + 1 ed = (p-1)(q-1) + 1 ed=(p1)(q1)+1

化简得:

e d = p q − p − q + 1 + 1 ed = pq - p - q + 1+ 1 ed=pqpq+1+1

n = p q n = pq n=pq 带入原式得:

e d = n − p − q + 2 ed = n - p - q + 2 ed=npq+2

整理原式得

p + q = n − e d + 2 p + q = n - ed + 2 p+q=ned+2

插句闲话

我们把目光聚焦到题面的数据范围一栏,看到这句话

”以下记 m = n − e d + 2 m = n - ed + 2 m=ned+2。“

正好是化简后的 p + q p + q p+q

我当时看到这句话就知道,我的解法是正确的!

话说回来

现在已知

{ p + q = n − e d + 2 p q = n \begin{cases} p + q = n - ed + 2\\ pq = n \end{cases} {p+q=ned+2pq=n

要求 p p p q q q

其中 n , e , d n,e,d n,e,d 为常数。

如果我们能推出 p − q p - q pq,那么问题就迎刃而解了。

初一党是不是熟悉了起来?

忘了?不要紧,我们来复习一下。

完全平方和: ( a + b ) 2 = a 2 + 2 a b + b 2 (a + b)^2 = a^2 + 2ab + b^2 (a+b)2=a2+2ab+b2

完全平方差: ( a − b ) 2 = a 2 − 2 a b + b 2 (a - b)^2 = a^2 - 2ab + b^2 (ab)2=a22ab+b2

现在已知 a b ab ab a + b a + b a+b,我们如何求出 a − b a - b ab 呢?

我们来把完全平方和减去完全平方差试试:

( a + b ) 2 − ( a − b ) 2 = ( a 2 + 2 a b + b 2 ) − ( a 2 − 2 a b + b 2 ) (a + b)^2 - (a - b)^2 = (a^2 + 2ab + b^2) - (a^2 -2ab + b^2) (a+b)2(ab)2=(a2+2ab+b2)(a22ab+b2)

等号右边化简得:

( a + b ) 2 − ( a − b ) 2 = a 2 + 2 a b + b 2 − a 2 + 2 a b + b 2 (a + b)^2 - (a - b)^2 = a^2 + 2ab + b^2 - a^2 +2ab + b^2 (a+b)2(ab)2=a2+2ab+b2a2+2ab+b2

合并同类项得:

( a + b ) 2 − ( a − b ) 2 = 4 a b (a + b)^2 - (a - b)^2 = 4ab (a+b)2(ab)2=4ab

挪一挪项得:

( a + b ) 2 − 4 a b = ( a − b ) 2 (a + b)^2 - 4ab = (a - b)^2 (a+b)24ab=(ab)2

交换左右两边得:

( a − b ) 2 = ( a + b ) 2 − 4 a b (a - b)^2 = (a + b)^2 - 4ab (ab)2=(a+b)24ab

左边脱掉平方得:

a − b = ± ( a + b ) 2 − 4 a b a - b = \pm \sqrt{(a + b)^2 - 4ab} ab=±(a+b)24ab

已知 a b ab ab p q pq pq a + b a + b a+b p + q p + q p+q,就能求出 a − b a-b ab p − q p - q pq 了!

补充解释

由于 p p p q q q 的大小关系无关紧要——题目中只说了打印 p p p q q q 两者中较大的再打印两者中较小的。 p p p 我们在这里先假设它为 p p p q q q 两者中较大的数, q q q p p p q q q 中的较小数,因此下文中 p − q p - q pq 没有正负号。


n = p q n = pq n=pq n − e × d + 2 = p + q n - e \times d + 2 = p + q ne×d+2=p+q 带入得:

{ p + q = n − e d + 2 p − q = ( n − e d + 2 ) 2 − 4 n \begin{cases} p + q = n - ed + 2\\ p - q = \sqrt{(n - ed + 2)^2 - 4n} \end{cases} {p+q=ned+2pq=(ned+2)24n

我们设上面一行为 1 式,下面一行为 2 式,我们将 1 式 + 2 式得到的 3 式为:

2 p = n − e d + 2 + ( n − e d + 2 ) 2 − 4 n 2p = n - ed + 2 + \sqrt{(n - ed + 2)^2 - 4n} 2p=ned+2+(ned+2)24n

等式两边同除以2得:

p = n − e d + 2 + ( n − e d + 2 ) 2 − 4 n 2 p = \frac{n - ed + 2 + \sqrt{(n - ed + 2)^2 - 4n}}{2} p=2ned+2+(ned+2)24n

将 1 式做个小小的变动得:

q = n − e d + 2 − p q = n - ed + 2 - p q=ned+2p

此时 p p p 是已知的, n − e × d + 2 n - e \times d + 2 ne×d+2 为常数,所以可以解出 q q q 为:

q = n − e d + 2 − n − e d + 2 + ( n − e d + 2 ) 2 − 4 n 2 q = n - ed + 2 - \frac{n - ed + 2 + \sqrt{(n - ed + 2)^2 - 4n}}{2} q=ned+22ned+2+(ned+2)24n

这里可以化简得:

q = n − e × d + 2 − ( n − e × d + 2 ) 2 − 4 n 2 q = \frac{n - e \times d + 2 -\sqrt{(n - e \times d + 2)^2 - 4n}}{2} q=2ne×d+2(ne×d+2)24n

最终得:

{ p = n − e d + 2 + ( n − e d + 2 ) 2 − 4 n 2 q = n − e d + 2 − ( n − e d + 2 ) 2 − 4 n 2 \begin{cases} p = \frac{n - ed + 2 + \sqrt{(n - ed + 2)^2 - 4n}}{2}\\ q = \frac{n - ed + 2 -\sqrt{(n - ed + 2)^2 - 4n}}{2} \end{cases} p=2ned+2+(ned+2)24n q=2ned+2(ned+2)24n

再看到题目要求, p p p q q q 要求是正整数。因为我们知道,如果平方根不是正数,只可能是 0、正有理数、无理数(平方开不尽)、不在实数范围内的虚数(被开方数小于 0)。

0 好办,我们只需要算出 p p p q q q 之后特判就可以了。对于小数和无理数,我们可以先用 long long 强制转换,舍弃小数点后带入题目给出的两个式子,检验解是否正确。对于虚数,函数 sqrt 的被开方数为负数的时候会返回 NaN,用 long long 储存 NaN 时值为 0,和我们处理 P = 0 P = 0 P=0 时思路一样。如果解符合上述条件,那么一定是整数,也就是符合题目要求的解。

那时间复杂度如何保证呢?加减乘除运算都是 O ( 1 ) O(1) O(1) 的,sqrt 函数也是 O ( 1 ) O(1) O(1) 级别的,故单次询问时间复杂度为 O ( 1 ) O(1) O(1),总询问复杂度为 O ( k ) O(k) O(k),最大运算量为 1 0 5 10^5 105,故能轻松通过此题。

思路部分完结撒花!

代码

边上代码边讲!

//
//  main.cpp
//  P8814 [CSP-J 2022] 解密(民间数据)
//
//  Created by SkyWave Sun on 2022/11/7.
//

#include <iostream>
#include <cmath>
#include <algorithm>
using namespace std;

int main(int argc, const char * argv[]) {
    int k;
    scanf("%d",&k);
    while (k--) {
        long long n,e,d;
        scanf("%lld%lld%lld",&n,&e,&d);
        long long PsubQ = sqrt((n - e * d + 2) * (n - e * d + 2) - (n * 4));//算出 P - Q
        long long PaddQ = n - e * d + 2;//算出 P + Q
        long long P = (PsubQ + PaddQ) / 2;// P = (P + Q + P - Q) / 2
        long long Q = PaddQ - P;//Q = P + Q - P
        if (P * Q == n && e * d == (P - 1) * (Q - 1) + 1 && P && Q) {//检验
            printf("%lld %lld\n",min(P, Q),max(P, Q));//先输出小的再输出大的
            printf("NO\n");
        }
    }
    return 0;
}

完结撒花!

我是 SkyWave,这是我的第三篇题解,有不足之处请多多指出,有任何看不懂的地方欢迎留言或者私信!

  • 8
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值