Processing math: 3%

B-Quadratic equation_2019牛客暑期多校训练营(第九场)

题意

解下列方程
(x+y)b mod p
(x\ *\ y) \equiv c \ mod \ p

题解

y = b-x 带入二式
x * (b-x) \equiv c \ mod \ p
bx - x^2 =c + kp
x^2 - bx + c + kp = 0
解得x = \frac{b \ \pm \ \sqrt{b^2 - 4c+kp} }{2}
要使x为整数则\sqrt{b^2 - 4c+kp}要为整数
z = \sqrt{b^2 - 4c+kp}
z^2 = b^2 - 4c+kp
z^2 \equiv \ b^2 - 4c \ mod \ p
问题就变成了二次剩余
先判断是否有解也就是b^2-4c是否是p的二次剩余
利用欧拉准则:当且仅当d^{\frac{p-1}{2}} \equiv 1 \ mod \ pdp的二次剩余
当且仅当d^{\frac{p-1}{2}} \equiv -1 \ mod \ pdp的非二次剩余
接下来套二次剩余板子求z即可,有一种特殊情况当p \ \% \ 4 = 3时可以用公式z = d^{\frac{p+1}{4}} \% \ p快速求解
现在x = \frac{b + z}{2}, y = \frac{b - z}{2},可能不是整数,我们对x和y都乘上一个偶数(p+1)就可以保证x,y是整数且仍然满足题目的两个方程,因为
(x+y)*(p+1) \ \%\ p =(x+y) \% p\ *\ (p+1) \% p = b*1 = b
x*(p+1)*y*(p+1)\%p = (x*y)\%p\ *\ (p^2+2p+1)\%p = c*1 = c

*顺带扒了一下咖啡鸡的板子

代码

#include <bits/stdc++.h>
 
using namespace std;
typedef long long ll;
const ll mod = 1e9+7;
 
ll pow_mod(ll a, ll b) {
    ll ans = 1;
    while (b > 0) {
        if (b & 1) ans = ans * a % mod;
        a = a * a % mod;
        b /= 2;
    }
    return ans;
}
 
int main() {
    int T;
    scanf("%d", &T);
 
    while (T--) {
        ll b, c;
        scanf("%lld%lld", &b, &c);
        ll t = ((b*b - 4*c) % mod + mod) % mod;
        if (pow_mod(t, (mod-1)/2) == mod-1) puts("-1 -1");
        else {
            ll z = pow_mod(t, (mod+1)/4);
            ll x = ((b + z) % mod + mod) % mod;
            ll y = ((b - z) % mod + mod) % mod;
            x = x * (mod+1) / 2 % mod;
            y = y * (mod+1) / 2 % mod;
            if (x > y) swap(x, y);
            printf("%lld %lld\n", x, y);
        }
    }
    return 0;
}

二次剩余模板

//调用solve(d, p)返回x
mt19937_64 gen(time(0));
struct T{ll x,y;};
ll w;
T mul_two(T a,T b,ll p){
    T ans;
    ans.x=(a.x*b.x%p+a.y*b.y%p*w%p)%p;
    ans.y=(a.x*b.y%p+a.y*b.x%p)%p;
    return ans;
}
  
T qpow_two(T a,ll n,ll p){
    T ans;
    ans.x=1;
    ans.y=0;
    while(n){
        if(n&1) ans=mul_two(ans,a,p);
        n>>=1;
        a=mul_two(a,a,p);
    }
    return ans;
}
  
ll qpow(ll a,ll n,ll p){
    ll ans=1;
    a%=p;
    while(n){
        if(n&1) ans=ans*a%p;
        n>>=1;
        a=a*a%p;
    }
    return ans%p;
}
  
ll Legendre(ll a,ll p){
    return qpow(a,(p-1)>>1,p);
}
  
int solve(ll n,ll p){
    if (n==0) return 0;
    if (n==1) return 1;
    if(Legendre(n,p)+1==p) return -1;
    ll a,t;
    while(1){
        a=gen()%p;
        t=a*a-n;
        w=(t%p+p)%p;
        if(Legendre(w,p)+1==p) break;
    }
    T tmp;
    tmp.x=a;
    tmp.y=1;
    T ans=qpow_two(tmp,(p+1)>>1,p);
    return ans.x;
}
posted @   奔跑的蜗new  阅读(186)  评论(0)    收藏  举报
编辑推荐:
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题
· 记一次 .NET某固高运动卡测试 卡慢分析
· 微服务架构学习与思考:微服务拆分的原则
· 记一次 .NET某云HIS系统 CPU爆高分析
· 如果单表数据量大,只能考虑分库分表吗?
阅读排行:
· 7 个最近很火的开源项目「GitHub 热点速览」
· DeepSeekV3:写代码很强了
· MySQL下200GB大表备份,利用传输表空间解决停服发版表备份问题
· Visual Studio 2022 v17.13新版发布:强化稳定性和安全,助力 .NET 开发提
· AI浏览器自动化实战
点击右上角即可分享
微信分享提示