[牛客多校第九場]Quadratic equation(二次剩餘)

在這裏插入圖片描述

題意:

給定兩個數字在模1e9 + 7意義下x + y的和以及x和y的乘積,求x和y

題目分析

由於x和y的取值範圍,我們可以得到x + y的範圍爲 0 <= x + y < 2 * p,那麼對於第一個式子我們可以得到: x + y = b 或者 x + y = p + b的兩種情況.
對於第一種情況,將第一個式子代入第二個式子可得
y * (b - y) = k * p + c
移項得,y ^ 2 - b * y + k * p + c = 0
如果y要有整數解,當且僅當 b ^ b - 4 * (k * p + c) 爲完全平方數,從而得到如下方程
a ^ 2 = b * b - 4 * (k * p + c)
對兩邊同時模p可得
a ^ 2 ≡b * b - 4 * c (mod p)
從而轉化爲一個二次剩餘的問題

二次剩餘:

當時比賽的時候用下面的博客魔改了一下過了,博客裏邊有簡單的證明
https://blog.csdn.net/acdreamers/article/details/10182281
在比賽之後又參考了下邊的博客,才真正理解了這個神奇的東西
https://blog.csdn.net/a_crazy_czy/article/details/51959546

Part one 二次剩餘的基本概念

在數論中,特別在同餘理論裏,一個整數 d\bm{d}對另一個整數 p\bm{p} 的二次剩餘(英語:Quadratic residue)指X的平方 X2\bm{X^2} 除以p\bm{p}得到的餘數。
當存在某個 X\bm{X}X2d(modp)\bm{X^2≡d(mod p) } 式子成立時,稱 “ d\bm{d} 是模 p\bm{p} 的二次剩餘 ”
當對任意 X\bm{X},上式都不成立時,稱 “ d\bm{d} 是模 p\bm{p} 的二次非剩餘 ”

關於二次剩餘的判定,可以用歐拉準則來判斷,具體方法如下:

p 是奇質數且 p 不能整除 d ,則:
d 是模 p 的二次剩餘當且僅當:dp121(modp)\bm{d^\frac{p-1}{2}≡ 1(mod p)}
d 是模 p 的二次非剩餘當且僅當:dp121(modp)\bm{d^\frac{p-1}{2}≡ -1(mod p)}
以勒讓德符號表示,即爲:dp12(dp)modp{\displaystyle d^{\frac {p-1}{2}}\equiv\left({\frac {d}{p}}\right){mod {p}}}
其中勒讓德符號的定義如下:在這裏插入圖片描述

歐拉從充分性和必要性兩個方面證明了上述結論,給出的證明如下:

首先,由於p{\displaystyle p}是一個奇素數,由費馬小定理, dp11(modp){\displaystyle d^{p-1}\equiv 1{\pmod {p}}}。但是 p1{\displaystyle} p-1是一個偶數,
所以有(dp121)(dp12+1)0(modp){\displaystyle (d^{\frac {p-1}{2}}-1)\cdot (d^{\frac {p-1}{2}}+1)\equiv 0{\pmod {p}}}
p{\displaystyle}p是一個素數,所以 dp121{\displaystyle d^{\frac {p-1}{2}}-1}dp12+1{\displaystyle d^{\frac {p-1}{2}}+1}中必有一個是 p{\displaystyle }p 的倍數。因此 dp12{\displaystyle d^{\frac {p-1}{2}}}p{\displaystyle p}的餘數必然是111-1

必要性:

證明若 d{\displaystyle} d是模 p{\displaystyle} p的二次剩餘,則 dp121(modp){\displaystyle d^{\frac {p-1}{2}}\equiv 1{\pmod {p}}}
d{\displaystyle } d是模 p{\displaystyle } p的二次剩餘,則存在 x2d(modp){\displaystyle x^{2}\equiv d{\pmod {p}}}p{\displaystyle } pd,x{\displaystyle d,x}互質。根據費馬小定理得:
dp12xp11(modp){\displaystyle d^{\frac {p-1}{2}}\equiv x^{p-1}\equiv 1{\pmod {p}}}

充分性:

證明若 dp121(modp){\displaystyle d^{\frac {p-1}{2}}\equiv 1{\pmod {p}}},則 d{\displaystyle } d是模 p{\displaystyle } p的二次剩餘p{\displaystyle } p是一個奇素數,所以關於 p{\displaystyle } p的原根存在。設 a{\displaystyle } ap{\displaystyle } p的一個原根,
則存在 1jp1{\displaystyle 1\leq j\leq p-1},使得 d=ajd=aj{\displaystyle d=a^{j}} {\displaystyle d=a^{j}}
於是 ajp121(modp){\displaystyle a^{j{\frac {p-1}{2}}}\equiv 1{\pmod {p}}}
a{\displaystyle } ap{\displaystyle }p的一個原根,因此 a{\displaystyle } ap{\displaystyle } p的指數是 p1{\displaystyle} p-1,於是 p1{\displaystyle} p-1整除 j(p1)2{\displaystyle {\frac {j(p-1)}{2}}}。這說明 j{\displaystyle } j是一個偶數。令 i=j2{\displaystyle i={\frac {j}{2}}},就有 (ai)2=a2i=d{\displaystyle (a^{i})^{2}=a^{2i}=d}d{\displaystyle } d是模 p{\displaystyle } p的二次剩餘。

Part two 二次剩餘的問題求解(隨機大法好!)

問題描述:
對於給定的 ddpp 判斷 dd 是否是 pp 的二次剩餘,
如果是,則輸出X2d(modp)X^2\equiv d{\pmod {p}}的一個解,
其中,pp 是奇素數。
題目傳送門:http://acm.timus.ru/problem.aspx?space=1&num=1132

引理:

對於0&lt;=X&lt;=p1,Xp121(modp)0 &lt;= X &lt; = p - 1,X^{\frac{p - 1}{2}}\equiv 1{\pmod {p}}p12{\frac{p - 1}{2}}個解
證明如下:
u,vu,vXX的兩個解,我們可以得到u2v20(modp)u^2 - v ^ 2\equiv 0{\pmod{p}}
進一步化簡得到(uv)(u+v)0(modp)(u - v)*(u + v)\equiv0{\pmod{p}},由XX的範圍我們可以指導,
p(u+v)p | (u + v),並且u+v=pu + v = p,所以有p12{\frac{p - 1}{2}}個解。

Cipolla算法

爲了求出XX的解,我們通過隨機數找到一個滿足(an2p)(\frac{a - n ^ 2}{p})爲-1的根據引理我們可以知道這樣的aa一共有p12\frac{p - 1}{2}個,因此求出這樣的aa的期望次數爲p12p\frac{p - 1}{2 p}約爲12\frac{1}{2},基本上我們隨機兩次就可以得到這樣的aa,一般我們會隨機比較多的次數防止自己臉黑。
在的得到這樣的一個aa之後我們做如下的處理:

①取a2n\sqrt{a ^ 2 - n}爲基本的虛數單位,設爲ww,類比1\sqrt{-1}作爲 ii
②構造一個與當前虛數單位所對應的數域,類比於實數到複數,則在這個數域中所有的數字都可以表示爲a+bwa + bw的形式
③驗證當前數域的運算的封閉性、交換律、結合律、分配律,即驗證它是一個合法的數域

在這裏插入圖片描述
對於這個數域,我們可以得到如下的結論:
wpw(modp)w^p\equiv-w{\pmod{p}}
證明:根據(w2p)(\frac{w ^ 2}{p})1-1我們可以知道,w2p121(modp){w^2}^{\frac{p-1}{2}}\equiv -1\pmod{p},從而我們知道wp=wp1w,wpw(modp)w^p = w ^{p - 1} * w,w^p\equiv-w\pmod p
(a+b)pap+bp(modp)(a + b) ^ p \equiv a ^ p + b ^ p{\pmod p}
證明見我之前寫的題解:https://blog.csdn.net/z472421519/article/details/99842319

我們取X(a+w)p+12(modp)X \equiv (a + w) ^{\frac{p + 1}{2}}\pmod p
我們可以得到X2(a+w)p+1(modp)X ^ 2 \equiv(a + w)^{p + 1} \pmod pX2(a+w)p(a+w)(modp)X ^ 2 \equiv(a + w)^{p} * (a + w) \pmod p
利用剛纔的結論X2(ap+wp)(a+w)(modp)X ^ 2 \equiv(a^p + w^p) * (a + w) \pmod pX2(apw)(a+w)(modp)X ^ 2 \equiv(a^p-w) * (a + w) \pmod p
再利用費馬小定理apa(modp)a ^ p \equiv a \pmod p 得到,
X2(aw)(a+w)(modp)X ^ 2 \equiv(a - w) * (a + w) \pmod p
X2(a2w2)(modp)X ^ 2 \equiv(a^2 - w^2) \pmod p
代入w=anw = \sqrt{a - n}
X2n(modp)X ^ 2 \equiv n \pmod p,即XX滿足之前的二次剩餘方程

代碼

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <iostream>
#include <math.h>

using namespace std;
typedef long long LL;

LL quick_mod(LL a, LL b, LL m)
{
    LL ans = 1;
    a %= m;
    while(b)
    {
        if(b & 1)
        {
            ans = ans * a % m;
            b--;
        }
        b >>= 1;
        a = a * a % m;
    }
    return ans;
}

struct T
{
    LL p, d;
};

LL w;

//二次域乘法
T multi_er(T a, T b, LL m)
{
    T ans;
    ans.p = (a.p * b.p % m + a.d * b.d % m * w % m) % m;
    ans.d = (a.p * b.d % m + a.d * b.p % m) % m;
    return ans;
}

//二次域上快速冪
T power(T a, LL b, LL m)
{
    T ans;
    ans.p = 1;
    ans.d = 0;
    while(b)
    {
        if(b & 1)
        {
            ans = multi_er(ans, a, m);
            b--;
        }
        b >>= 1;
        a = multi_er(a, a, m);
    }
    return ans;
}

//求勒讓德符號
LL Legendre(LL a, LL p)
{
    return quick_mod(a, (p-1)>>1, p);
}

LL mod(LL a, LL m)
{
    a %= m;
    if(a < 0) a += m;
    return a;
}

LL Solve(LL n,LL p)
{
    if(p == 2) return 1;
    if (Legendre(n, p) + 1 == p)
        return -1;
    LL a = -1, t;
    while(true)
    {
        a = rand() % p;
        t = a * a - n;
        w = mod(t, p);
        if(Legendre(w, p) + 1 == p) break;
    }
    T tmp;
    tmp.p = a;
    tmp.d = 1;
    T ans = power(tmp, (p + 1)>>1, p);
    return ans.p;
}

int main()
{
    LL t;
    scanf("%d", &t);
    while(t--)
    {
        LL n,p,N;
        LL x,y;
        scanf("%lld%lld",&x,&y);
        p = 1e9 + 7;
        n = x * x - 4 * y;
        N = (x + p) * (x + p) - 4 * y;
//        //printf("%lld",n);
        if(n == 0)
        {
            printf("%lld %lld\n",x / 2,x / 2);
            continue;
        }
        LL a;
        LL X,Y;
        bool suc = false;
        for(int i = 1;i <= 10;i++)
        {
            if(n > 0)
            {
                a = Solve(n, p);
                X = (x - a) / 2,Y = (x + a) / 2;
                if(((X + Y) % p == (x % p) && (X * Y) % p == y) && (X >= 0 && X <= p) && (Y >= 0 && Y <= p))
                {
                    suc = true;
                    break;
                }
            }
            if(N > 0)
            {
                a = Solve(N, p);
                X = (x + p - a) / 2,Y = (x + p + a) / 2;
                if(((X + Y) % p == (x % p) && (X * Y) % p == y) && (X >= 0 && X <= p) && (Y >= 0 && Y <= p))
                {
                    suc = true;
                    break;
                }
            }
        }
        if(suc)
            printf("%lld %lld\n",X,Y);
        else
            printf("-1 -1\n");
     }
    return 0;
}

不知道爲啥有的時候會出錯,考慮到隨機算法的臉黑性,我加了個暴力判斷,在運算超過十次之後就直接1,1-1,-1輸出

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章