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


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

    二次剩余

    给定 $ 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('
    ');
    	}
    	return 0;
    }
    }
    int main(){return RKK::main();}
    

    应用

    不知道(?)

  • 相关阅读:
    CSS3的box-sizing属性
    html5 --基础笔记2
    html5--基础笔记
    CSS3--阴影,渐变,背景图片
    响应式布局--流式布局
    angular中的this指向问题
    angular中控制器之间的通讯方式
    angular中的$http配置和参数
    console
    h5表单验证的css和js方法
  • 原文地址:https://www.cnblogs.com/rikurika/p/13357240.html
Copyright © 2020-2023  润新知