二次剩余定理及Cipolla算法入门到自闭

二次剩余定义:

在维基百科中,是这样说的:如果q等于一个数的平方模 n,则q为模 n 意义下的二次剩余。例如:x2≡n(mod p)。否则,则q为模n意义下的二次非剩余。

Cipolla算法:一个解决二次剩余强有力的工具,用来求得上式的x的一个算法。

需要学习的数论及数学基础:勒让德符号欧拉判别准则复数运算

勒让德符号:判断n是否为p的二次剩余,p为奇质数。

欧拉定理为xφ(p)≡1(mod p)

当p为素数时,可知φ(p)=p-1,转化为xp-1≡1(mod p)

开根号后为 x(p1)/2≡±1(mod p),如果等于1就肯定开的了方,为-1一定开不了。所以x是否为n的二次剩余就用这个欧拉判别准则。

qpow(n,(mod-1)>>1)==mod-1

随机找数a,使得a2−n为复数的虚数单位的平方,即

随机一个数a,然后对a2−n进行开方操作(就是计算他勒让德符号的值),直到他们的勒让德符号为-1为止(就是开不了方为止)。 就是找到一个a满足(a2−n)(p1)/2=−1。

    LL a=1;
    while(qpow((a*a-n+mod)%mod,(mod-1)>>1)!=mod-1)  a=rand()%mod;

建立复数乘法运算((a+bi)(c+di)=(ac+bd*(-1))+(bc+ad)i)

建立一个类似的域,前面寻找了一个a使(a2−n)(p1)/2=−1,所以我们定义ω=√(a2−n)。那么现在的ω也像i一样,满足ω2=a2−n=-1

node two(node a,node b)//复数相乘
{
    node ans;
    ans.x=(a.x*b.x%mod+a.y*b.y%mod*w%mod)%mod;
    ans.y=(a.x*b.y%mod+a.y*b.x%mod)%mod;
    return ans;
}

答案=(a+ω)(p+1)/2

根据拉格朗日定理,可以得出虚数处的系数一定为0。

 1 node q_pow(node a,LL b){
 2     node res;
 3     res.x=1,res.y=0;
 4     while(b){
 5         if(b&1)res=two(res,a);
 6         a=two(a,a);
 7         b>>=1;
 8     }
 9     return res;
10 }
1     node p;
2     p.x=a,p.y=1,w=(a*a-n+mod)%mod;
3     node ans=q_pow(p,(mod+1)>>1);
4     return ans.x;

2019牛客多校训练营第九场B题为Cipolla算法模板题

 1 #include<bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const LL mod=1e9+7;
 5 struct node
 6 {
 7     LL x,y;
 8 };
 9 LL w;
10 node two(node a,node b)//复数相乘
11 {
12     node ans;
13     ans.x=(a.x*b.x%mod+a.y*b.y%mod*w%mod)%mod;
14     ans.y=(a.x*b.y%mod+a.y*b.x%mod)%mod;
15     return ans;
16 }
17 node q_pow(node a,LL b)
18 {
19     node res;
20     res.x=1,res.y=0;
21     while(b)
22     {
23         if(b&1)
24             res=two(res,a);
25         a=two(a,a);
26         b>>=1;
27     }
28     return res;
29 }
30 LL qpow(LL a,LL b)
31 {
32     LL ans=1;
33     a%=mod;
34     while(b)
35     {
36         if(b&1)
37             ans=ans*a%mod;
38         a=a*a%mod,b>>=1;
39     }
40     return ans;
41 }
42 LL solve(LL n)
43 {
44     if(qpow(n,(mod-1)>>1)==mod-1)//勒让德符号
45         return -1;
46     else if(n==0)
47         return 0;
48     LL a=1;//找随机a
49     while(qpow((a*a-n+mod)%mod,(mod-1)>>1)!=mod-1)//勒让德符号
50         a=rand()%mod;
51     node p;
52     p.x=a,p.y=1,w=(a*a-n+mod)%mod;
53     node ans=q_pow(p,(mod+1)>>1);//求出答案
54     return ans.x;
55 }
56 int main()
57 {
58     int T;
59     scanf("%d",&T);
60     LL q,b,n,x,y,c,t=qpow(2,mod-2);
61     while(T--)
62     {
63         scanf("%lld%lld",&b,&c);
64         q=(b*b-4*c+mod)%mod;
65         n=solve(q);
66         if(n==-1)
67         {
68             printf("-1 -1\n");
69             continue;
70         }
71         x=((b+n)%mod)*t%mod,y=(b-x+mod)%mod;
72         if(x>y)
73             swap(x,y);
74         printf("%lld %lld\n",x,y);
75     }
76     return 0;
77 }

原文地址:https://www.cnblogs.com/Aamir-Dan/p/11392140.html

时间: 2024-11-05 22:39:46

二次剩余定理及Cipolla算法入门到自闭的相关文章

Cipolla算法学习小记

转自:http://blog.csdn.net/doyouseeman/article/details/52033204 简介 Cipolla算法是解决二次剩余强有力的工具,一个脑洞大开的算法. 认真看懂了,其实是一个很简单的算法,不过会感觉得出这个算法的数学家十分的机智. 基础数论储备 二次剩余 首先来看一个式子x2≡n(modp),我们现在给出n,要求求得x的值.如果可以求得,n为mod p的二次剩余,其实就是n在mod p意义下开的尽方.Cipolla就是一个用来求得上式的x的一个算法.

POJ-1061 青蛙的约会-数论扩展欧几里德算法入门及推导

Description 两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面.它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止.可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置.不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的.但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的.为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面. 我们把这

贝叶斯公式由浅入深大讲解—AI基础算法入门

1 贝叶斯方法 长久以来,人们对一件事情发生或不发生的概率,只有固定的0和1,即要么发生,要么不发生,从来不会去考虑某件事情发生的概率有多大,不发生的概率又是多大.而且概率虽然未知,但最起码是一个确定的值.比如如果问那时的人们一个问题:"有一个袋子,里面装着若干个白球和黑球,请问从袋子中取得白球的概率是多少?"他们会想都不用想,会立马告诉你,取出白球的概率就是1/2,要么取到白球,要么取不到白球,即θ只能有一个值,而且不论你取了多少次,取得白球的概率θ始终都是1/2,即不随观察结果X

HDU 1098 Ignatius&#39;s puzzle 费马小定理+扩展欧几里德算法

题目大意: 给定k,找到一个满足的a使任意的x都满足 f(x)=5*x^13+13*x^5+k*a*x 被65整除 推证: f(x) = (5*x^12 + 13 * x^4 + ak) * x 因为x可以任意取 那么不能总是满足 65|x 那么必须是 65 | (5*x^12 + 13 * x^4 + ak) 那么就是说 x^12 / 13 + x^4 / 5 + ak / 65 正好是一个整数 假设能找到满足的a , 那么将 ak / 65 分进x^12 / 13 + x^4 / 5中得到

第二章 算法入门 合并排序

在第二章中难的算法不多,接下来我会把稍微复杂一点的算法整理一下 #include <iostream> using namespace std; void mergeSort(int *A,int left,int mid,int right) { int *L=new int[mid-left+1]; int *R=new int[right-mid+1]; int i,j; for(i=0;i<mid-left+1;i++) { L[i]=A[left+i]; } for (j=0;

算法入门心得

最近看了刘汝佳写的算法入门经典  感觉自己的基础实在太烂了  所以总结了一些我们比较容易犯的错误给大家看看(大牛就不要看了O(∩_∩)O) 1.浮点数:两个整数计算的是浮点数的时候一定要把整数先化为浮点数  5-0.1计算机先把5变5.0之后再进行计算的 2.异或运算:这个是个很神秘的东西如果要在一个数组中找一个只有一个的数那么就可以用异或了 异或也可以用在两个数的交换a = a^b; b = a ^ b; a = a ^ b;就实现转换了 自己异或自己等于0: 3.逻辑运算符都是短路运算符a|

Cordic 算法入门

三角函数计算,Cordic 算法入门 三角函数的计算是个复杂的主题,有计算机之前,人们通常通过查找三角函数表来计算任意角度的三角函数的值.这种表格在人们刚刚产生三角函数的概念的时候就已经有了,它们通常是通过从已知值(比如sin(π/2)=1)开始并重复应用半角和和差公式而生成. 现在有了计算机,三角函数表便推出了历史的舞台.但是像我这样的喜欢刨根问底的人,不禁要问计算机又是如何计算三角函数值的呢.最容易想到的办法就是利用级数展开,比如泰勒级数来逼近三角函数,只要项数取得足够多就能以任意的精度来逼

算法入门经典第六章 例题6-14 Abbott的复仇(Abbott&#39;s Revenge)BFS算法实现

Sample Input 3 1 N 3 3 1 1 WL NR * 1 2 WLF NR ER * 1 3 NL ER * 2 1 SL WR NF * 2 2 SL WF ELF * 2 3 SFR EL * 0 Sample Output (3,1) (2,1) (1,1) (1,2) (2,2) (2,3) (1,3) (1,2) (1,1) (2,1) (2,2) (1,2) (1,3) (2,3) (3,3) 析 题目的大意是,输入起点,离开起点时的朝向和终点,求一条最短路. 每一个

写给嵌入式程序员的循环冗余校验(CRC)算法入门引导

写给嵌入式程序员的循环冗余校验(CRC)算法入门引导 http://blog.csdn.net/liyuanbhu/article/details/7882789 前言 CRC校验(循环冗余校验)是数据通讯中最常采用的校验方式.在嵌入式软件开发中,经常要用到CRC 算法对各种数据进行校验.因此,掌握基本的CRC算法应是嵌入式程序员的基本技能.可是,我认识的嵌入式程序员中能真正掌握CRC算法的人却很少,平常在项目中见到的CRC的代码多数都是那种效率非常低下的实现方式. 其实,在网上有一篇介绍CRC