• 二次剩余学习笔记


    二次剩余学习笔记

    看SCOI2018的时候发现不会这个东西
    来写模板与简单证明
    p是奇质数,偶的就那一个,就不讨论了

    二次剩余

    求解(x^2equiv n pmod p)

    勒让德符号

    (a^frac{P-1}{2}equiv left(frac{a}{p} ight) pmod p)

    (x^2equiv a pmod p)
    存在x时(x^{p-1}equiv 1 pmod p)
    所以(xequiv a^{frac{1}{2}}pmod p)(x^{p-1}equiv a^{frac{p-1}{2}}equiv 1pmod p)

    不存在x时(a^{frac{p-1}{2}})不能被表示成(x^{p-1}) ,于是这个东西就不等于1,又因为它的平方等于1,所以它就等于-1(膜意义下)

    cipolla算法

    首先随机a使得(a^2-n)不是二次剩余
    (omega =sqrt{a^2-n}),作为当前数域下单位根
    由于满足一系列性质,这个数域是成立的

    又因为(omega^2)不是二次剩余,由勒让德符号可知((w^2)^{frac{p-1}{2}}equiv w^{p-1} ot equiv 1pmod p)
    由费马小定理,((w^2)^{p-1}equiv 1 pmod p)
    所以(w^{p-1}equiv -1)

    于是就可以搞事情了

    有这样一个式子

    [(a+w)^{p+1} ]

    [equiv(a+w)^p(a+w) ]

    [equiv(sum_i a^iw^{p-i}C^i_p)(a+w) pmod p ]

    因为(i!=p,0)时组合数的阶乘p无法消掉(奇质数),所以(mod~p)之后为0

    [equiv (a^p+w^p)(a+w) pmod p ]

    由上面的结论和费马小定理:

    (w^{p-1}equiv -1)
    (a^{p-1}equiv 1)

    [equiv (a-w)(a+w) pmod p ]

    [equiv a^2-w^2pmod p ]

    [equiv a^2-(a^2-n)pmod p ]

    [equiv n pmod p ]

    整理得到

    [(x^2)equiv (a+w)^{frac{p+1}{2}*2}equiv (a+w)^{p+1}equiv n pmod p ]

    (x equiv pm (a+w)^{frac{p+1}{2}})

    可以证明其不含(w)

    代码实现

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cstdlib>
    #define ll long long 
    using namespace std;
    ll read(){
    	ll x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x; 
    }
    ll mod,n;
    ll i2;
    struct complex{
    	ll r,i;
    	complex(ll r=0,ll i=0):r(r),i(i){}
    	int operator == (complex y){
    		return r==y.r&&i==y.i;
    	}
    	complex operator *(complex y){
    		return complex((r*y.r%mod+i*y.i%mod*i2%mod)%mod,((r*y.i%mod+i*y.r)%mod)%mod); 
    	}
    }; 
    complex ksm(complex a,int b){
    	complex res=complex(1,0);
    	while(b){
    		if(b&1) res=res*a;
    		a=a*a;
    		b>>=1;
    	}
    	return res;
    }
    int check(int x){
    	return ksm(complex(x,0),(mod-1)/2)==1;
    }
    int R(int now){
    	return ((rand()<<15)+rand())%(now-1)+1;
    } 
    void solve(){
    	ll a=R(mod);
    	while(check((a*a+mod-n)%mod)) a=R(mod);
    	i2=(a*a%mod-n+mod)%mod;
    	ll x0=ksm(complex(a,1),(mod+1)/2).r;
    	printf("%lld ",min(x0,mod-x0));
    	printf("%lld
    ",max(x0,mod-x0)); 
    }
    int main(){
    	int T=read();
    	while(T--){
    		n=read(),mod=read();
    		if(n==0){
    			printf("%d
    ",0);continue;
    		}
    		if(!check(n)) printf("Hola!
    ");
    		else solve();
    	}
    	return 0;
    } 
    
  • 相关阅读:
    Linux下hook指定库
    一行一行往上爬
    高可用数据同步方案-SqlServer迁移Mysql实战
    Hystrix核心基础
    Fastjson解析多级泛型的几种方式—使用class文件来解析多级泛型
    面试大全之JVM篇
    云原生下的CICD
    学习Raft算法的笔记
    Go语言下的线程模型
    分布式事务解决方案以及 .Net Core 下的实现(上)
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/12055511.html
Copyright © 2020-2023  润新知