2019牛客暑期多校训练营(第九场——B Quadratic equation 二次剩余定理)

链接:https://ac.nowcoder.com/acm/contest/889/B
来源:牛客网

题目描述
Amy asks Mr. B problem B. Please help Mr. B to solve the following problem.

Let p = 1000000007.
Given two integers b and c, please find two integers x and y(0 \leq x \leq y < p)(0≤x≤y<p), such that
(x + y) \bmod p = b(x+y)modp=b
(x \times y) \bmod p = c(x×y)modp=c
输入描述:
The first line contains an integer t, which is the number of test cases (1 <= t <= 10).

In the following t lines, each line contains two integers b and c (0 <= b, c < p).
输出描述:
For each test case, please output x, y in one line.
If there is a solution, because x <= y, the solution is unique.

If there is no solution, please output -1, -1
示例1
输入
复制
10
4 4
5 6
10 10
10 25
20000 100000000
0 5
3 6
220 284
0 1
1000000000 1000000000
输出
复制
2 2
2 3
-1 -1
5 5
10000 10000
474848249 525151758
352077071 647922939
448762649 551237578
-1 -1
366417496 633582504

题目大意:

给定一个b,c,p (0<b,c<p)
(x+y)%p = b
(x*y)%p = c
求x y (0 x <=y<p )

解题思路:

首先得知道 二次同余方程
x² mod p == n 知道p和n是可以解出x的

(x-y)² mod p = (x+y)² mod p - 4*(xy)mod p
因为 (x+y)%p = b (x
y)%p = c
所以 (x-y)² mod p = (b^2 - 4c + 4p)mod p
所以 (x-y)² 和 b^2 - 4*c 同余 关于p

由: x² mod p == n
我们令 x = (x-y) 令n = (b^2 - 4c + 4p)mod p;
通过模板,这样我们就可以 解出 x-y = ? 设为 a。解有两个 a 和 p-a

因为 x,y<p 所以 x+y<2p
因为(x+y)%p = b 所以 x+y = b或者 x+y = b+p;

由上面解出的 x-y = a 加上 x+y = b||b+p 就能解出 x和y了。

需要注意的是,当 b^2-4*c==0时,这是 x-y 和 0同余 ,那么x-y = 0 即x=y 这个需要特判一下。

然后就是分类讨论各种情况了
x+y = b x-y = a
x+y = b x- y = p -a
x+y = b+p x-y = a
x+y = b+p x-y = p-a

AC代码:

#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll p = 1000000007;
ll qpow(ll a,ll b,ll p){
    ll ans=1;
    while(b){
        if(b&1) ans=ans*a%p;
        a=a*a%p;
        b>>=1;
    }
    return ans;
}
ll modsqr(ll a,ll n){
    ll b,k,i,x;
    if(n==2) return a%n;
    if(qpow(a,(n-1)/2,n) == 1){
        if(n%4 == 3){
            x=qpow(a,(n+1)/4,n);
        }
        else{
            for(b=1; qpow(b,(n-1)/2,n) == 1; b++);
            i = (n-1)/2;
            k=0;
            while(i%2==0){
                i /= 2,k /= 2;
                if((qpow(a,i,n)*qpow(b,k,n)+1)%n == 0) k += (n-1)/2;
            }
            x = qpow(a,(i+1)/2,n)*qpow(b,k/2,n)%n;
        }
        if(x*2 > n) x = n-x;
        return x;
    }
    return -1;
}
int main()
{
    int t;
    scanf("%d", &t);
    ll b,c;
    while(t--){
        scanf("%lld%lld",&b,&c);
        ll n = (b*b%p - (4*c)%p+4*p)%p;
        ll a = modsqr(n,p);
    	if(b*b - 4*c == 0) a = 0;
        if(a == -1){
        	cout<<"-1 -1"<<endl;
        	continue;
        }
        ll x,y;
        int flag = 0;
        for(ll i=0;i<=1;i++){	
        	if((i*p+b-a)%2==0){
	        	y = (i*p+b-a)/2;
	        	x = a+y;
	        	if(x>y) swap(x,y);
	        	if(x>=0&&x<p&&y>=0&&y<p){
	        		flag = 1;
	        		break;
	        	}
	        }
        }
        if(flag) cout<<x<<" "<<y<<endl;
        else{
        	a = p - a;
        	for(ll i=0;i<=1;i++){
	        	if((i*p+b-a)%2==0){
		        	y = (i*p+b-a)/2;
		        	x = a+y;
		        	if(x>y) swap(x,y);
		        	if(x>=0&&x<p&&y>=0&&y<p){
		        		flag = 1;
		        		break;
		        	}
		        }
        	}
        	if(!flag) cout<<"-1 -1"<<endl;
        	else cout<<x<<" "<<y<<endl;
	    }
	}
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值