知识点简单总结——二次剩余

知识点简单总结——二次剩余

二次剩余

给定 $ n,p $ ,求 $ a,0 \le a < p,a^{2} \equiv n (mod \ p) $ ,其中 $ p $ 为奇素数。

欧拉准则

判断二次剩余的存在性。

众所周知根据费马小定理有 $ n^{p-1} \equiv 1 (mod \ p) $ 。

那么就有 $ ( n ^ { \frac{ p-1 }{ 2 } } ) ^ {2} - 1 \equiv 0 (mod \ p) $ 。

很明显 $ n ^ { \frac{ p-1 }{ 2 } } $ 只可能是 $ 1 $ 或 $ -1 $ 。

性感理解可以证明只有上式结果为 $ 1 $ 时有二次剩余(被打)

利用原根容易证明上式为 $ 1 $ 是存在二次剩余的充要条件。

Cipolla算法

随机找到一个 $ a , a^{2} - n $ 非二次剩余,期望大约 $ 2 $ 次找到符合条件的 $ a $ 。

设 $ i ,i ^ {2} \equiv a ^ {2} - n $ 。

定义成类似虚部的东西。

有 $ (a+i) ^ {p+1} \equiv n $ ,证明:

引理1: $ i^{p}\equiv - i $ ,证明: $ i^{p} = i( a^{ 2 } - n )^{ \frac{p-1}{2} } \equiv - i $ 。

引理2: $ (A+B)^{p} \equiv A^{p} + B^{p} $ ,证明略。

于是有 $ (a+i)^{p+1} \equiv ( a^{p} + i^{p} )(a+i) \equiv (a-i)(a+i) \equiv n $ 。

只需要求出 $ (a+i)^{ \frac{p+1}{2} } $ 即可。

至于为什么结果不含虚部,参见https://kewth.github.io/2019/10/21/二次剩余/

注意二次剩余可能有两个,互为相反数。

#include<bits/stdc++.h>
using namespace std;
typedef long long lint;
template<typename TP>inline void read(TP &tar)
{
    TP ret=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){ret=ret*10+(ch-'0');ch=getchar();}
    tar=ret*f;
}
struct pat{lint x,y;pat(lint x=1,lint y=0):x(x),y(y){}};
pat mul(pat a,pat b,lint w,lint p){return pat((a.x*b.x%p+a.y*b.y%p*w%p)%p,(a.x*b.y%p+a.y*b.x%p)%p);}
namespace RKK
{
lint fpow(lint a,lint b,lint p){lint ret=1;while(b){if(b&1ll)ret=ret*a%p;a=a*a%p,b>>=1;}return ret;}
lint fpow(pat a,lint b,lint w,lint p){pat ret;while(b){if(b&1ll)ret=mul(ret,a,w,p);a=mul(a,a,w,p),b>>=1;}return ret.x;}
lint fuck(lint n,lint p)
{
    if(p==2) return n%p;
    n%=p;if(fpow(n,p-1>>1,p)==p-1) return -1;
    lint a,w;
    while(1)
    {
        a=rand(),w=(a*a%p-n+p)%p;
        if(fpow(w,p-1>>1,p)==p-1) break;
    }
    return fpow(pat(a,1),p+1>>1,w,p);
}
int main()
{
    srand(time(NULL));
    int TAT;read(TAT);while(TAT--)
    {
        lint n,p;read(n),read(p);if(!n){puts("0");continue;}
        lint ans=fuck(n,p);if(ans==-1){puts("Hola!");continue;}
        if(p-ans<ans) ans=p-ans;
        printf("%lld ",ans);if(p-ans!=ans) printf("%lld",p-ans);putchar('\n');
    }
    return 0;
}
}
int main(){return RKK::main();}

应用

不知道(?)

原文链接: https://www.cnblogs.com/rikurika/p/13357240.html

欢迎关注

微信关注下方公众号,第一时间获取干货硬货;公众号内回复【pdf】免费获取数百本计算机经典书籍;

也有高质量的技术群,里面有嵌入式、搜广推等BAT大佬

    知识点简单总结——二次剩余

原创文章受到原创版权保护。转载请注明出处:https://www.ccppcoding.com/archives/369384

非原创文章文中已经注明原地址,如有侵权,联系删除

关注公众号【高性能架构探索】,第一时间获取最新文章

转载文章受原作者版权保护。转载请注明原作者出处!

(0)
上一篇 2023年3月2日 下午6:55
下一篇 2023年3月2日 下午6:55

相关推荐