• 二次剩余


    二次剩余

    PS:以下内容大概都是抄的。
    大概是解这样一个方程:

    [x^2 equiv n pmod p ]

     
    这里讨论 (p) 为奇素数。

    称非 (0)(n) 是二次剩余当 (n) 存在上述方程的解,反之成为非二次剩余。

    二次剩余的数量为 (frac{p-1}{2}),原因是这样的:

    1.若一个数 (n) 为二次剩余,设它有两组解,(x_1,x_2)
    那么 (x_1^2 equiv x_2^2 equiv n),由平方差公式得到 ((x_1-x_2)(x_1+x_2) equiv 0)
    那么 (x_1 equiv -x_2),因为 (p) 为奇素数,所以 (x_1 eq x_2)

    2.若 (n) 为二次剩余,存在解 (x)(-x) 也为解。

    欧拉准则

    大概是判断一个数 (n) 是否是二次剩余。

    做法是这样的,求 (n^{frac{p-1}{2}}),若为 (1) 则是,否则不是。

    首先有这样一个事情,(n^{p-1} equiv 1),则 ((n^{frac{p-1}{2}})^2 equiv 1)
    若其取值为 (1),可以令 (n=g^k),其中 (g) 为原根。
    则有 (g^{kfrac{p-1}{2}} equiv 1),即 ((p-1)| kfrac{p-1}{2})
    (2|k),所以 (n) 为二次剩余。

    然后还有这样一个事情,若 (n) 为二次剩余,则存在 (x^2 equiv n)
    (n^{frac{p-1}{2}}equiv x^{p-1} equiv 1)
    所以 (n^{frac{p-1}{2}}equiv 1)(n) 是二次剩余是等价的条件。

    故可以通过 (n^{frac{p-1}{2}})(1)(-1) 来判断 (n) 是否为二次剩余。

    Cipolla

    大概是对于 (n) 为二次剩余,找到 (x) 满足 (x^2 equiv n)

    做法是这样的,首先找到一个 (a),满足 (a^2-n) 为非二次剩余,这个过程通过随机并检验即可实现。
    定义一个类似虚部的东西 (i),满足 (i^2 equiv a^2-n)
    然后有 ((a+i)^{p+1} equiv n)((a+i)^{frac{p+1}{2}}equiv x)

    有这样一些事情:

    1.((A+B)^p=A^p + B^p)
    通过二项式定理展开为 (sum limits_{j=0}^{p} A^j B^{p-j} inom{p}{j})
    其中 (inom{p}{j}) 中的质因子 (p) 只在 (j=0,j=p) 时不存在。

    [egin{align*} i^p&=i(i^2)^{frac{p-1}{2}}\ &=i(a^2-n)^{frac{p-1}{2}}\ &=-i\ end{align*}]

    这样的话考虑 ((a+i)^{p+1}) 这个东西。
    可以展开为 ((a+i)^p(a+i)=(a^p+i^p)(a+i)=(a-i)(a+i)=a^2-i^2=n)
    ((a+i)^{frac{p+1}{2}})(-(a+i)^{frac{p+1}{2}}) 是两个解。

    可以证明 ((a+i)^{frac{p+1}{2}}) 不存在虚部。
    假设虚部存在,则有 ((x+yi)^2=n,y eq 0)
    展开得 (x^2+y^2(a^2-n)-n=2xy)
    其中左侧不含虚部,故 (y eq 0,x=0)
    代入得到 (y^2i^2=n),显然无解,与假设不成立。
     
     

    #include<bits/stdc++.h>
    #define ll long long
    using namespace std;
    int mod,n,a;
    struct node{
    	ll r,i;
    	node(int r=0,int i=0):r(r),i(i){}
    };
    inline node operator * (const node &x,const node &y){
    	return node((x.r*y.r%mod+x.i*y.i%mod*(1ll*a*a%mod-n+mod))%mod,(x.r*y.i+x.i*y.r)%mod);
    }
    inline ll qpow(ll x,int k,ll r=1){
    	for(;k;k>>=1,x=x*x%mod) if(k&1) r=r*x%mod;
    	return r;
    }
    inline node qpow(node x,int k,node r=node(1,0)){
    	for(;k;k>>=1,x=x*x) if(k&1) r=r*x;
    	return r;
    }
    bool check(int x){
    	return qpow(x,mod-1>>1)==1;
    }
    int main(){
    	int T; scanf("%d",&T);
    	while(T--){
    		scanf("%d%d",&n,&mod);
    		if(!n){ puts("0"); continue; }
    		if(!check(n)){ puts("Hola!"); continue; }
    		for(a=rand()%(mod-1)+1;check((1ll*a*a-n+mod)%mod);a=rand()%(mod-1)+1);
    		int x=qpow(node(a,1),mod+1>>1).r,y=mod-x; if(y<x) swap(x,y);
    		printf("%d %d
    ",x,y);
    	}
    	return 0;
    }
  • 相关阅读:
    c#数据结构与算法
    学习资源---.NET
    怎样完全删除sqlserver
    树,森林 二叉树之间转化 原理
    ref 和out 区别
    GridView批量删除记录、全选及弹出确认对话框
    .NET基础 小记--------2013.8.10
    Xml 读写
    同步 异步 区别
    委托学习
  • 原文地址:https://www.cnblogs.com/skyh/p/13357396.html
Copyright © 2020-2023  润新知