zoukankan      html  css  js  c++  java
  • 【Timus1132】—Square Root(奇质数意义下的二次剩余)

    传送门


    SolutionSolution

    首先:
    勒让德符号:

    (ap)={1a%p1a%p0a0(%p) (frac{a}{p})= egin{cases} 1 & a是\%p意义下的二次剩余 \ -1 & a是\%p意义下的非二次剩余\ 0 & aequiv 0(\%p)\ end{cases}

    有结论(欧拉准则)
    (ap)ap12(frac{a}{p})equiv a^{frac{p-1}{2}}

    证明

    a0(%p)aequiv0(\%p)时显然成立

    由于费马小定理:ap11a^{p-1}equiv 1
    所以ap121 or 1(%p)a^{frac{p-1}{2}}equiv1 {or} -1(\%p)

    首先证明(ap)=1(frac{a}{p})=1ap12=1a^{frac{p-1}{2}}=1

    必要性:

    由于ax2,aequiv x^2,ap12(x2)p12xp11(%p)a^{frac{p-1}{2}}equiv(x^2)^{frac{p-1}{2}}equiv x^{p-1}equiv 1(\%p)

    充分性:

    %p\%p意义下原根为gg,则gkap11(%p)g^kequiv a^{p-1}equiv 1(\%p)
    则一定存在giag^iequiv a

    gi(p1)2=1g^{frac{i(p-1)}{2}}=1
    gp11g^{p-1}equiv 1
    所以2i2|i
    所以必然存在gi2x0(%p)g^{frac{i}{2}}equiv x_0(\%p)

    (ap)=1(frac{a}{p})=-1
    反证可以得到xp11(%p)x^{p-1}equiv -1(\%p),显然是不可能的

    所以我们可以判断kk%p\%p意义下是否存在二次剩余


    CipollaCipolla算法

    求解pp为奇质数的情况

    随机一个数bb
    使wb2awequiv b^2-a且不存在二次剩余

    由于ww%p\%p不存在二次剩余
    可以类似虚数那样设i=wi=sqrt w

    由于b2wax2b^2-wequiv aequiv x^2
    b2wb2i2(b+i)(bi)b^2-wequiv b^2-i^2equiv (b+i)(b-i)

    考虑(b+i)p=j=0p(pj)bjipj(b+i)^p=sum_{j=0}^{p}{pchoose j}b^ji^{p-j}
    由于当j!=0 or pj!=0 {or} p时,(pj)0{pchoose j}equiv 0

    所以(b+i)pbp+ipbp1b+wp12i(b+i)^pequiv b^p+i^pequiv b^{p-1}b+w^{frac{p-1}{2}}i
    由于ww%p\%p非二次剩余,所以wp121w^{frac{p-1}{2}}equiv -1

    所以(b+i)pbi(b+i)^pequiv b-i
    所以x2(b+i)(bi)(b+i)p+1x^2equiv (b+i)(b-i)equiv (b+i)^{p+1}
    x(b+i)p+12xequiv (b+i)^{frac{p+1}{2}}

    由于%p\%p意义下非二次剩余不会少于O(p2)O(frac p 2)
    所以期望找2次bb就存在ww是非二次剩余

    复杂度O(logp)O(log_p)


    #include<bits/stdc++.h>
    using namespace std;
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    #define ll long long
    #define cs const
    #define pii pair<int,int>
    #define fi first
    #define se second
    #define pb push_back
    int mod,w;
    inline int add(int a,int b){return (a+=b)>=mod?a-mod:a;}
    inline void Add(int &a,int b){(a+=b)>=mod?(a-=mod):0;}
    inline int dec(int a,int b){return (a-=b)<0?a+mod:a;}
    inline void Dec(int &a,int b){(a-=b)<0?a+=mod:0;}
    inline int mul(int a,int b){return 1ll*a*b>=mod?1ll*a*b%mod:a*b;}
    inline void Mul(int &a,int b){a=mul(a,b);}
    inline int ksm(int a,int b,int res=1){
    	for(;b;b>>=1,a=mul(a,a))(b&1)&&(res=mul(res,a));return res;
    }
    struct plx{
    	int x,y;
    	plx(int _x=1,int _y=0):x(_x),y(_y){}
    	friend inline plx operator *(cs plx &a,cs plx &b){
    		return plx(add(mul(a.x,b.x),mul(mul(a.y,b.y),w)),add(mul(a.x,b.y),mul(a.y,b.x)));
    	}
    }; 
    inline plx ksm(plx a,int b){
    	plx res=plx();
    	for(;b;b>>=1,a=a*a)if(b&1)res=res*a;
    	return res;
    }
    inline int solve(int a){
    	if(mod==2)return 1;
    	if(ksm(a,(mod-1)/2)==mod-1)return -1;
    	int b;
    	while(1){
    		b=rand()%mod;
    		w=dec(mul(b,b),a);
    		if(ksm(w,(mod-1)/2)==mod-1)break;
    	}
    	return ksm(plx(b,1),(mod+1)/2).x;
    }
    int main(){
    	int T=read();
    	srand(time(NULL));
    	while(T--){
    		int a=read();mod=read();a%=mod;
    		a=solve(a);
    		if(a!=-1){
    			int b=mod-a;
    			if(a>b)swap(a,b);
    			if(a!=b)cout<<a<<" "<<b<<'
    ';
    			else cout<<a<<'
    ';
    		}
    		else cout<<"No root
    ";
    	}
    }
    
  • 相关阅读:
    进程隐藏类
    MFC中一些使用的方法
    c++/vc++的一些学习方法
    随意更改桌面壁纸
    Winsock异步模型之(事件通知模型 WSAAsyncSelect)
    开发外挂的一些原理
    ios 图片
    得到cell的坐标
    取出字符串中的空格
    ios 获取当前的日期,年月日
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/12328756.html
Copyright © 2011-2022 走看看