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;
}

 

posted @ 2024-06-19 11:05  五月江城  阅读(460)  评论(0编辑  收藏  举报