传送:https://ac.nowcoder.com/acm/contest/889/B
题意:
已知方程组:
$(x+y) mod p=b$
$(x*y) mod p=c$。
现在给出$b,c$,$p=1e9+7$。求解$x,y(x<=y)$。
分析:
先不考虑取模的条件。那么两个等式求解两个变量,可以化为一元二次方程:$b^2-4*c={x-y}^2$。
那么等于就是求解这样一个式子:$t^2=b^2-4*c$。(同时有取模)
用的是陈老师的板子。
那么求解出对于方程的两个解$ans1,ans2$。此时这两个解是$|x-y|$。那么就需要枚举两种,和为$b$或者$b+mod$。
1 #include<cstdio> 2 #include<algorithm> 3 #include<iostream> 4 using namespace std; 5 typedef long long ll; 6 const ll mod=1e9+7; 7 ll pow_mod(ll x,ll y,ll mod){ 8 ll res=1,base=x; 9 while (y){ 10 if (y&1) (res*=base)%=mod; 11 (base*=base)%=mod; 12 y>>=1; 13 } 14 return res; 15 } 16 ll b,c,ans1,ans2; 17 ll work(ll n, ll p) { 18 if (n == 0){ //特判x=y 19 ans1=0;ans2=p-ans1; 20 return ans1; 21 } 22 //if (p == 2) return (n & 1) ? 1 : -1; 23 if (pow_mod(n, p >> 1, p) != 1) return -1; 24 if (p & 2){ 25 ans1=pow_mod(n, p + 1 >> 2, p);ans2=p-ans1; 26 return ans1; 27 } 28 int s = __builtin_ctzll(p ^ 1); 29 ll q = p >> s, z = 2; 30 for (; pow_mod(z, p >> 1, p) == 1; ++z); 31 ll c = pow_mod(z, q, p); 32 ll r = pow_mod(n, q + 1 >> 1, p); 33 ll t = pow_mod(n, q, p), tmp; 34 for (int m = s, i; t != 1;) { 35 for (i = 0, tmp = t; tmp != 1; ++i) tmp = tmp * tmp % p; 36 for (; i < --m;) c = c * c % p; 37 r = r * c % p; 38 c = c * c % p; 39 t = t * c % p; 40 } 41 ans1=r; ans2=p-r; 42 return r; 43 } 44 bool solve(ll del,ll sum){ //del=|x-y|,sum=x+y 45 int f1=(del&1),f2=(sum&1); //奇偶性相同 46 if(f1!=f2) return false; 47 ll x=(del+sum)/2,y=(sum-del)/2; 48 if(x>y) swap(x,y); 49 if((x+y)%mod!=b||(x*y)%mod!=c) return 0; 50 if(!(x>=0&&x<mod&&y>=0&&y<mod)) return 0; 51 printf("%lld %lld ",x,y); 52 return 1; 53 } 54 int main() 55 { 56 int T;scanf("%d",&T); 57 while(T--) 58 { 59 scanf("%lld%lld",&b,&c); 60 ll t=((b*b-4*c)%mod+mod)%mod; 61 if(work(t,mod)==-1) {puts("-1 -1");continue;} 62 int flag=0; 63 flag=solve(ans1,b);if(flag) continue; //和为b或b+mod 64 flag=solve(ans1,mod+b);if(flag) continue; 65 flag=solve(ans2,b);if(flag) continue; 66 flag=solve(ans2,mod+b);if(flag) continue; 67 if(!flag) puts("-1 -1"); 68 } 69 }