CSP历年复赛题-P8814 [CSP-J 2022] 解密
原题链接:https://www.luogu.com.cn/problem/P8814
题意解读:根据公式计算p,q的值。
解题思路:
已知
1、n = pq
2、ed = (p-1)(q-1) + 1 => ed = pq - p - q + 2
由1、2左右相减可得到:
n - ed = p + q - 2 => p + q = n - ed + 2 = m
所以有:p + q = m,pq = n,m<=10^9,n<=10^18
方法一:暴力枚举
枚举p,q,范围都是1~m,大概能得40分
方法二:解方程
p + q = m,pq = n
q = m - p,p(m-p) = n, p^2 - mp + n = 0
根据一元二次方程求根公式ax^2 + bx + c = 0,x = (-b + sqrt(b^2- 4ac)) / 2a 或者 x = (-b - sqrt(b^2- 4ac)) / 2a
p = (m + sqrt(m^2 - 4n)) / 2 或者 p = (m - sqrt(m^2 - 4n)) / 2,由于p<=q,所以p = (m - sqrt(m^2 - 4n)) / 2
剩下的只需要判断m^2 - 4n是否是完全平方数,然后(m - sqrt(m^2 - 4n))能否整除2,再算出p、q的值即可。
方法三:二分答案
根据p + q = m,pq = n,p <= q,可知当p越小,pq就越小,p越大,pq就越大,根据此单调性可以实现二分
可以二分p,范围是1~m/2
计算q = m - p
判断当p * q == n时找到答案
如果p * q < n,我们知道 p+q值固定且p <= q,要让pq更大,必须p更接近q,所以l = mid + 1
如果p * q > n,就要让pq更小,必须p与q相差更大,p就要更小,所以r = mid - 1
注意:全程使用long long更保险
100分代码:
#include <bits/stdc++.h>
using namespace std;
long long k, n, d, e, m;
int main()
{
cin >> k;
while(k--)
{
cin >> n >> d >> e;
m = n - e * d + 2;
long long l = 1, r = m / 2, ans = -1;
while(l <= r)
{
long long p = (l + r) >> 1;
long long q = m - p;
if(p * q == n)
{
ans = p;
break;
}
else if(p * q < n) l = p + 1;
else r = p - 1;
}
if(ans == -1) cout << "NO" << endl;
else cout << ans << " " << m - ans << endl;
}
return 0;
}