题目描述
给定一个正整数 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=(pi−1)(qi−1)+1。
思路
这道题可以看成一道数学题(还有其他解法,不过我不会 )。
看到题目先化简 ed:
e
d
=
(
p
−
1
)
(
q
−
1
)
+
1
ed = (p-1)(q-1) + 1
ed=(p−1)(q−1)+1
化简得:
e
d
=
p
q
−
p
−
q
+
2
ed = pq - p - q + 2
ed=pq−p−q+2
将 n = pq 带入原式得:
e
d
=
n
−
p
−
q
+
2
ed = n - p - q + 2
ed=n−p−q+2
整理原式得
p
+
q
=
n
−
e
d
+
2
p + q = n - ed + 2
p+q=n−ed+2
现在已知
{
p
+
q
=
n
−
e
d
+
2
p
q
=
n
\begin{cases} p+q=n-ed+2\\ pq=n\\ \end{cases}
{p+q=n−ed+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)²−(p−q)²=(p²+2pq+q²)−(p²−2pq+q²)=p²+2pq+q²−p²+2pq−q²=4pq
(
p
+
q
)
²
−
(
p
−
q
)
²
=
4
p
q
\begin{aligned} (p+q)²-(p-q)²&=4pq \\ \end{aligned}
(p+q)²−(p−q)²=4pq
(
p
+
q
)
²
−
4
p
q
=
(
p
−
q
)
²
\begin{aligned} (p+q)²-4pq &=(p-q)²\\ \end{aligned}
(p+q)²−4pq=(p−q)²
交换左右两项可得:
(
p
−
q
)
=
(
p
+
q
)
²
−
4
p
q
\begin{aligned} (p-q) &=(p+q)²-4pq\\ \end{aligned}
(p−q)=(p+q)²−4pq
左边脱掉平方得:
p
−
q
=
±
(
p
+
q
)
²
−
4
p
q
p-q=\pm\sqrt{(p+q)²-4pq}
p−q=±(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=n−ed+2p−q=(n−ed+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=n−ed+2+(n−ed+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=2n−ed+2+(n−ed+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=2n−ed+2−(n−ed+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=2n−ed+2+(n−ed+2)²−4nq=2n−ed+2−(n−ed+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;
}
完结撒花✿✿ヽ(°▽°)ノ✿