题目链接:
https://ac.nowcoder.com/acm/contest/889/B?&headNav=acm
题目思路:
注意到 0 <= x <= y <= p ,很明显有两种情况,一种是x+y = b,一种是x + y = p + b 。
那么我们先讨论x+y=c的情况,此时有 y = b - x 。
带入 x * y % p = c ,可知 x(b-x)= k * p + c ,可以发现是一个二次函数,而且对称轴等于 b / 2 , 所以可以看出这种情况下,x
和y是关于b/2对称的,我们可以设这个距离是dis。
此时出现了分数,那么方程两边同时乘以4, 通过拆项、移项可以得到
此时可以二次剩余求出2*dis , 那么就可以求出两个答案了。
有一种特殊情况就是b*b==4*c 的情况,这种情况回到最原始的方程可以得出一定是0,那么就可以了。
还有上边提到了x+y=p+b的情况,其实细心观察这种情况和上边的情况重了,因为加上那个p最后也会被模掉。
(以后我再忘记乘逆元我就是傻逼)
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9+7;
ll pow_mod(ll a,ll b, ll mod)
{
ll ans=1;
while(b){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
ll modsqr(ll a,ll n)
{
ll b,k,i,x;
if(n==2)return a%n;
if(pow_mod(a, (n-1)/2 , n)==1){
if(n % 4 == 3)
x=pow_mod(a, (n+1)/4 ,n);
else{
for(b=1 ; pow_mod(b, (n-1)/2 ,n )==1 ;b++);
i=(n-1)/2;
k=0;
do{
i /=2;
k /=2;
if( (pow_mod(a,i,n) * (ll)pow_mod(b,k,n)+1 )% n ==0 )
k+=(n-1)/2;
}
while(i%2==0);
x = (pow_mod(a,(i+1)/2,n) * (ll)pow_mod(b,k/2,n) )%n;
}
if(x*2 > n)
x=n-x;
return x;
}
return -1;
}
int main()
{
int t;
scanf("%d",&t);
ll inv2=pow_mod(2,mod-2,mod);
while(t--)
{
ll b,c;
scanf("%lld%lld",&b,&c);
ll res = b;
ll now = (((res*res)%mod - 4*c)%mod + mod )%mod ;
ll ans = modsqr(now,mod);
// cout<<now<<endl;
ll ret = (res - ans+mod)%mod;
if((b*b-4*c)%mod==0){
printf("%lld %lld\n",b/2,b/2);
continue;
}
if(ans != -1){
printf("%lld %lld\n",min(ret*inv2%mod,(res-(ret*inv2%mod)+mod)%mod),max(ret*inv2%mod,(res-(ret*inv2%mod)+mod)%mod) );
continue;
}
printf("-1 -1\n");
}
}