[CSP-J 2022] 解密 题解

题目描述

给定一个正整数 k k k,有 k k k 次询问,每次给定三个正整数 n i , e i , d i n_i, e_i, d_i ni,ei,di,求两个正整数 p i , q i p_i, q_i pi,qi,使 n i = p i × q i n_i = p_i \times q_i ni=pi×qi e i × d i = ( p i − 1 ) ( q i − 1 ) + 1 e_i \times d_i = (p_i - 1)(q_i - 1) + 1 ei×di=(pi1)(qi1)+1

思路

这道题可以看成一道数学题(还有其他解法,不过我不会 )。
看到题目先化简 ed:
e d = ( p − 1 ) ( q − 1 ) + 1 ed = (p-1)(q-1) + 1 ed=(p1)(q1)+1
化简得:
e d = p q − p − q + 2 ed = pq - p - q + 2 ed=pqpq+2
将 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

现在已知
{ 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、q。

其中 n,e,d 为常数。

如果我们能推出 p - q,那么问题就迎刃而解了。
我们运用一下完全平方公式(初二会学,没学的,建议学一下再看下面的内容)

( p + q ) ² − ( p − q ) ² = ( p ² + 2 p q + q ² ) − ( p ² − 2 p q + q ² ) = p ² + 2 p q + q ² − p ² + 2 p q − q ² = 4 p q \begin{aligned} (p+q)²−(p−q)²&=(p²+2pq+q²)-(p²-2pq+q²) \\ &=p²+2pq+q²-p²+2pq-q²\\ &=4pq \end{aligned} (p+q)²(pq)²=(p²+2pq+q²)(p²2pq+q²)=p²+2pq+q²p²+2pqq²=4pq
( p + q ) ² − ( p − q ) ² = 4 p q \begin{aligned} (p+q)²-(p-q)²&=4pq \\ \end{aligned} (p+q)²(pq)²=4pq
( p + q ) ² − 4 p q = ( p − q ) ² \begin{aligned} (p+q)²-4pq &=(p-q)²\\ \end{aligned} (p+q)²4pq=(pq)²
交换左右两项可得:
( p − q ) = ( p + q ) ² − 4 p q \begin{aligned} (p-q) &=(p+q)²-4pq\\ \end{aligned} (pq)=(p+q)²4pq
左边脱掉平方得:
p − q = ± ( p + q ) ² − 4 p q p-q=\pm\sqrt{(p+q)²-4pq} pq=±(p+q)²4pq
​将 n = pq,n - e *d + 2 = p + q=p+q 带入得:
{ p + q = n − e d + 2 p − q = ( n − e d + 2 ) ² − 4 n \begin{cases} p+q=n−ed+2\\ p-q=\sqrt{(n−ed+2)²-4n} \end{cases} {p+q=ned+2pq=(ned+2)²4n
然后我们将上下两个式子加起来,就得到了
2 p = n − e d + 2 + ( n − e d + 2 ) ² − 4 n \begin{aligned} 2p=n-ed+2+\sqrt{(n−ed+2)²-4n} \end{aligned} 2p=ned+2+(ned+2)²4n
再同时除以2:
p = n − e d + 2 + ( n − e d + 2 ) ² − 4 n 2 \begin{aligned} p= \frac{n-ed+2+\sqrt{(n−ed+2)²-4n} }{2} \end{aligned} p=2ned+2+(ned+2)²4n
这时,我们得出了p,也知道n−e×d+2 为常数,所以可以解出 q 为:
q = n − e d + 2 − ( n − e d + 2 ) ² − 4 n 2 \begin{aligned} q= \frac{n-ed+2-\sqrt{(n−ed+2)²-4n} }{2} \end{aligned} q=2ned+2(ned+2)²4n
就这样,我们可以得到:
{ p = n − e d + 2 + ( n − e d + 2 ) ² − 4 n 2 q = n − e d + 2 − ( n − e d + 2 ) ² − 4 n 2 \begin{cases} p= \frac{n-ed+2+\sqrt{(n−ed+2)²-4n} }{2}\\ q= \frac{n-ed+2-\sqrt{(n−ed+2)²-4n} }{2} \end{cases} p=2ned+2+(ned+2)²4n q=2ned+2(ned+2)²4n
再看到题目要求,p、q 要求是正整数。因为我们知道,如果平方根不是正数,只可能是 0、正有理数、无理数(平方开不尽)、不在实数范围内的虚数(被开方数小于 0)。

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

那时间复杂度如何保证呢?加减乘除都是 O(1) 的,sqrt 也是 O(1) 级别的,所以单次询问时间复杂度为 O(1),总询问复杂度为 O(k),最大运算量为 10^5,所以不会超时。

思路就到这里了,下面就是代码啦!

代码

#include<bits/stdc++.h>
using namespace std;
long long n,d,e,t;
int main(){
	//freopen("ans.in","r",stdin);
	//freopen("ans.out","w",stdout);
	cin>>t;
	while(t--){
		cin>>n>>d>>e;
		long long delta=(n-e*d+2)*(n-e*d+2)-4*n;
		if(delta<0){//特判 
			cout<<"NO"<<endl;
			continue;
		}
		long long p=1.0*((n-e*d+2)-sqrt(delta))/2;//p要小于q 
		long long q=1.0*((n-e*d+2)+sqrt(delta))/2;
		if(p>0 && q>0 && p*q==n && e*d==(p-1)*(q-1)+1){//判断p和q合不合理 
			cout<<p<<" "<<q<<endl;
		}
		else {
			cout<<"NO"<<endl;
		}
	}
	return 0;
}

完结撒花✿✿ヽ(°▽°)ノ✿

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈美漩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值