2019牛客暑期多校训练营(第九场)B Quadratic equation (平方剩余)

\((x+y)\equiv b\pmod p\)

\((x\times y)\equiv c\pmod p\)

由第一个式子可知:\(x+y=b~or~x+y=b+p\)

先任选一个代入到第二个式子里得

\[(x\times(b-x))\equiv c\pmod p \Rightarrow (2*x-b)^2\equiv (b^2-4c)\pmod p \]

解二次剩余方程 \(q^2\equiv a\pmod p\)

因为这个方程去查了很多资料

1. 欧拉准则

对于\(x^2\equiv a\pmod p\)

\[a^{p-1\over 2} = \begin{cases} 1\pmod p & {如果存在一个x使得a \equiv x^2 \pmod p}\\ -1\pmod p & {如果不存在x使得上式成立} \end{cases} \]

证明:

先不考虑a为0的情况。

已知 \((p-x)^2\equiv x^2\pmod p\), 这是因为\(p^2-2xp+x^2\equiv x^2 \pmod p\)

所有有\(p-1\over 2\) 个不同的二次剩余,即\(1^2,2^2,\cdots,({p-1\over 2}) \pmod p\) (因为前一半和后一半相同了)

\(a^{p-1}\equiv 1 \pmod p\), 可以写为\(({a^{p-1\over 2}-1})({a^{p-1\over 2}} + 1)\equiv 0\pmod p\)

上式中的前后两个因子,必须有一个为0,由\(Lagrangs's theorem\) 可知 k次多项式最多 k 个解,所以\(a^{p-1\over 2}-1\equiv 0\pmod p\) 有最多 \(p-1\over 2\)个解。

\(x^2\equiv a\), 所以\(a^{p-1\over 2} \equiv (x^2)^{p-1\over 2} \equiv 1\pmod p\)

所以每一个平方剩余都可以使得第一个因子为0,非0平方剩余最少有\(p-1\over 2\)个,所以这与上面方程的解正好对应起来,也就是说使得\(a^{p-1\over 2}\equiv 1\)成立的\(a\) 都是\(p\) 的二次剩余。同理可知使得\(a^{p-1\over 2} \equiv -1\)成立的\(a\)都是\(p\)的非二次剩余。

2. 求解二次剩余

本题比较特殊,\(p\equiv 3\pmod 4\) ,那么根据上面推出来的

\[a^{p-1\over 2}\equiv1~\Rightarrow~ a^{p+1\over 2}\equiv x^2~\Rightarrow a^{p+1\over 4}\equiv x \]

对于更一般的\(p\) , 可以参考: http://xbgjxt.swu.edu.cn/jsuns/html/jsuns/2019/1/201901009.htm

综述:

  1. 根据欧拉准则来判断是否有解
  2. 有解则求出原题中的x 与 y输出
  3. 无解则输出-1

标程代码:

int t, p = 1000000007;
//快速幂代码
long long pow(long long x, long long y, long long p) {
}
int main() {
    cin >> t;
    for (int tt = 0; tt < t; tt++) {
        long long b, c;
        cin >> b >> c;
        long long d = (b * b - 4 * c) % p;
        if (d < 0) {
            d += p;
        }
        if (d != 0 && pow(d, (p - 1) / 2, p) != 1) {//如果无解,需要注意d为0的情况
            cout << -1 << ' ' << -1 << endl;
        } else {
            long long r = pow(d, (p + 1) / 4, p);
            long long x = (b + r) * pow(2, p - 2, p) % p;
            long long y = (b - r) * pow(2, p - 2, p) % p;
            if (x < 0)x += p;
            if (y < 0)y += p;
            if (x > y) swap(x, y);
            cout << x << ' ' << y << endl;
        }
    }
}

自己的代码

const ll mod = 1e9+7;
ll pow_mod(ll a,ll i,ll n){
    if(i == 0)return 1 % n;
    ll tmp = pow_mod(a, i>> 1,n);
    tmp = tmp * tmp % n;
    if(i & 1)tmp = tmp * a % n;
    return tmp;
}
//红宝书模板代码,求解模p下二次剩余为a的解
ll modsqr(ll a,ll n){
    if(a == 0)return 0;
    ll b,k,i,x;
    if(n == 2)return a % n;
    if(pow_mod(a,(n-1)/2,n) == 1){
        if(n % 4 == 3)//本题中只会进入下面这个case
            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) * pow_mod(b,k,n) + 1) % n == 0)
                    k += (n-1) / 2;
            }while(i % 2 == 0);
            x = (pow_mod(a,(i+1)/2,n) * pow_mod(b,k/2,n))%n;
        }
        if(x * 2 > n)x = n-x;
        return x;
    }
    return -1;
}
int main() 
{
    int T;cin>>T;
    while(T--){
        ll b,c;
        scanf("%lld%lld",&b,&c);
        ll q,a;
        a = ((b*b - c * 4)%mod + mod) % mod;
        q = modsqr(a,mod);
        if(q == -1){//无解情况
            puts("-1 -1");
            continue;
        }
        //很蠢的分了两种情况....其实乘一个2的逆元即可
        ll x = (q + b) / 2;
        ll y = mod + b - x;
        x = (x % mod + mod) % mod;
        y = (y % mod + mod) % mod;
        if((x * y) % mod == c){
            if(x > y)swap(x,y);
            printf("%lld %lld\n",x,y);continue;
        }
        x = (q + b + mod)/2;
        y = b - x;
        x = (x % mod + mod) % mod;
        y = (y % mod + mod) % mod;
        if((x * y) % mod == c){
            if(x > y)swap(x,y);
            printf("%lld %lld\n",x,y);continue;
        }
        puts("-1 -1");
    }
    return 0;
}

参考资料:

https://en.wikipedia.org/wiki/Quadratic_residue

https://en.wikipedia.org/wiki/Euler's_criterion

posted @ 2019-08-20 13:53  kpole  阅读(290)  评论(0编辑  收藏  举报