题目:

[CSP-J 2022] 解密

[CSP-J 2022] 解密

前置知识

整式的加减乘除 —— 初一

题目解析

尽管我没有参加比赛

但我做这道题看到

ni=pi×qi,ei×di=(pi1)(qi1)+1n_i = p_i \times q_i, \: e_i \times d_i = (p_i - 1)(q_i - 1) + 1

首先化简eded:

ei×di=(pi1)(qi1)+1e_i \times d_i = (p_i - 1)(q_i - 1) + 1

化简得到:

ed=pqpq+2ed = pq - p - q + 2

n=p×qn = p \times q带入原式可得:

ed=npq+2ed = n - p - q + 2

整理原式可得:

p+q=ned+2p + q = n - ed + 2

已知:

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

要求 p,qp, q

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

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

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

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

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

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

我们用完全平方和减去完全平方差试试

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

等号右边化简得:

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

合并同类项得:

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

移项得:

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

交换等号两边得:

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

左边脱掉平方得

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

已知 ababpqpqa+ba+bp+qp+q,就能求出 aba-bpqp-q 了!

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

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

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

代码

#include <bits/stdc++.h>
using namespace std;

int main() {
	long long k;
	cin >> k;
	for (register int i = 1; i <= k; i++) {
		long long n, e, d;
		cin >> n >> e >> d;
		long long p = ((sqrt((n - e * d + 2) * (n - e * d + 2) - (n * 4))) + (n - e * d + 2)) / 2;
		long long q = (n - e * d + 2) - p;
		if (p * q == n && e * d == (p - 1) * (q - 1) + 1 && p > 0 && q > 0) {
			cout << (p < q ? p : q) << ' ' << (p > q ? p : q) << endl;
		} else {
			cout << "NO" << endl;
		}
	}
	return 0;
}