牛客多校第九场 B Quadratic equation 模平方根

题意:

已知

$x+y$ $mod$ $q = b$

$x*y$ $mod$ $q = c$

已知b和c,求x和y

题解:

容易想到$b^2-4c=x^2-2xy+y^2=(x-y)^2$

那么开个根号就能得到x-y,很容易就得出x和y了

在模q意义下对k开根号的方法就是找到w,使得$w*w$ $mod$ $q=k$

考虑模数q为奇质数的情况,可以用Tonelli-Shanks算法求解,这是一个概率算法,但是一般而言得出正确解的概率非常高,遇到类似问题套版即可。

#include<iostream>
#include<cmath>
#define MOD 1000000007
#define LL long long
using namespace std;
LL  qpow(LL x,LL y,LL m){
    //cal x^y%m
        LL re = 1;
        while(y){
            if(y & 1)//判断n的最后一位是否为1
                re = (re * x) % m;
            y >>= 1;//舍去n的最后一位
            x = (x * x) % m;//将a平方
        }
        return re % m;
    }
class ModSqrt{
    public:
    LL  power(LL x,LL y,LL m){
    //cal x^y%m
        LL re = 1;
        while(y){
            if(y & 1)//判断n的最后一位是否为1
                re = (re * x) % m;
            y >>= 1;//舍去n的最后一位
            x = (x * x) % m;//将a平方
        }
        return re % m;
    }
     
    LL normal_power(LL a,LL b){
        LL re = 1;
        while(b){
            if(b & 1)//判断n的最后一位是否为1
                re = (re * a);
            b>>= 1;//舍去n的最后一位
            a = (a * a);//将a平方
        }
        return re;
    }
     
    LL inverse(LL a,LL m){
        return power(a,m-2,m);
    }
     
    LL getn(LL p){
        for(LL i=2;i<p;i++){
            if(power(i,(p-1)/2,p)==p-1)
                return i;
        }
        return -1;
    }
     
     
    int solve(LL a,LL p){
    
        if(a==0)return 0;
        if(power(a,(p-1)/2,p)==p-1){
            return -1;
        }
        while(a<0)a+=p;
        while(a>p)a-=p;
        LL n=getn(p);
        bool finish=false;
        LL t=1;
        LL s=p-1;
        while(!finish){
            s=s/2;
            if(s%2) finish=true;
            else t+=1;
        }
        LL b=power(n,s,p);
        LL _a=inverse(a,p);
        LL x[66];
        for(LL i=0;i<66;i++)x[i]=0;
        x[t-1]=power(a,(s+1)/2,p); 
        for(LL i=1;i<=t-1;i++){
            LL judge=power((_a*x[t-i]*x[t-i])%p,normal_power(2,t-i-1),p);
            if(judge==1){
                x[t-i-1]=x[t-i];
            }else if(judge==p-1){
                x[t-i-1]=(power(b,normal_power(2,i-1),p)*x[t-i])%p;
            }
        }
        return x[0];
     
    }
}modsqrt;
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        LL b,c;
        scanf("%lld %lld",&b,&c);
        LL q=b*b%MOD-4*c%MOD;
        q=(q+MOD)%MOD;
        LL sq=modsqrt.solve(q,MOD);
        if(sq==-1)printf("-1 -1\n");
        else{
            LL xx=sq+b;
            LL yy=(b-sq+MOD)%MOD;
            LL x=xx*qpow(2,MOD-2,MOD)%MOD;
            LL y=yy*qpow(2,MOD-2,MOD)%MOD;
            if(x>y)swap(x,y);
            printf("%lld %lld\n",x,y);
        }
    }
    return 0;
}

 

posted @ 2019-08-15 21:44  Isakovsky  阅读(242)  评论(0编辑  收藏  举报