对于同余式

\[x^2 \equiv n \pmod p
\]

若对于给定的\(n, P\),存在\(x\)满足上面的式子,则乘\(n\)在模\(p\)意义下是二次剩余,否则为非二次剩余

我们需要计算的是在给定范围内所有满足条件的\(x\),同时为了方便,我们只讨论\(p\)是奇质数的情况

前置定理

  • \(x^2 \equiv (x+p)^2 \pmod p\)

证明:\(x^2 \equiv x^2 + 2xp + p^2 \pmod p\)显然成立

  • 对于\(x^2 \equiv n \pmod p\),除\(n=0\)外,总共有\(\frac{p-1}{2}\)个\(n\)使得该方程有解

我局的参考资料里对于这条性质的证明漏洞很大,所以下面的是自己yy的

根据第一个前置定理的式子,我们只需讨论\(x \in [1, p - 1]\)即可(当\(x=0\)时对应了\(n=0\)的特殊情况)

一个显然的性质是

\[x^2 \equiv (p - x)^2 \pmod p
\]

那么当\(x \in [1, \frac{p - 1}{2}]\)我们可以取到所有解。

接下来我们只需要证明当\(x\in[1, \frac{p-1}{2}]\)时\(x^2 \bmod p\)均两两不同

可以用反证法,若存在不同的\(u, v\)满足\(u^2 \equiv v^2 \pmod p\)

那么有\((u + v)(u - v) \equiv 0 \pmod p\)

显然\(-p < u + v < p\)且\(-p < u - v < p\)且\(u + v \not = 0, u - v \not = 0\),故该假设不成立,故原命题成立。

Q.E.D

  • 勒让德符号(Legender symbol)

\[(\frac{a}{p}) =
\begin{cases}
1 , &\text{a在模$p$意义下是二次剩余}\\
-1, &\text{a在模$p$意义下是非二次剩余}\\
0, &\text{a mod p = 0}
\end{cases}
\]

这个东西的分布大概是这个样子

计算公式

我局的这个公式就是构造出来的

\[(\frac{a}{p}) = a^{\frac{p - 1}{2}} \pmod p
\]

证明:

费马小定理:对于任意互质的\(x, p\),有\(x^{p - 1} = 1 \pmod p\)

一条同余式的性质:若\(a^k \equiv b^k \pmod p\),那么\(a^{kx} \equiv b^{xk} \pmod p\)

然后直接把这玩意儿带到\(x^2 \equiv a \pmod p\)里就行了

这里简单的写一下:

首先要明确我们的目的,我们现在要验证这个公式的正确性,也就是说我们要证明当\(a^{\frac{p-1}{2}}=1 \pmod p\)时满足条件的\(x\)存在,当\(a^{\frac{p-1}{2}}= -1 \pmod p\)时\(x\)不存在,当\(a^{\frac{p-1}{2}}= 0 \pmod p\)时\(a\mod p = 0\)

  1. 当\(a^{\frac{p-1}{2}}=1 \pmod p\)时

我们假设有\(x^2 \equiv a \pmod p\)

\[x^{2\frac{p-1}{2}} \equiv a^{\frac{p-1}{2}} \pmod p
\]

\[x^{p-1} \equiv 1 \pmod p
\]

根据费马小定理\(x\)显然存在,因此\(a\)是模\(p\)意义下的二次剩余

  1. 当\(a^{\frac{p-1}{2}}= -1 \pmod p\)时

假设有\(x^2 \equiv a \pmod p\)

同理可知

\[x^{p-1} \equiv -1 \pmod p
\]

显然\(x\)不存在,因此\(a\)不是模\(p\)意义下的二次剩余

  1. 当\(a^{\frac{p-1}{2}}= 0 \pmod p\)时

显然有\(a \bmod p = 0\)

Cipolla算法

算法流程

这个算法其实用两句话就能说完,但是背后的理论却非常高深(对于我这种菜鸡而言)。

  1. 首先使用随机的方法找到一个\((\frac{a^2 - n}{p}) = -1\),记\(\omega = \sqrt{a^2-n}\)

  2. 那么\(x \equiv (a + w)^{\frac{p+1}{2}} \pmod p\)

做完了。。。期望复杂度\(O(\log^2 n)\)

但是实际上实现起来并没有这么简单,因为要自定义类似于虚数的乘法/幂运算

算法理论

首先要有一点抽代基础(群/环/域什么的要知道定义)

我们来逐步分析这个算法(按照我的叙述风格应该是从发明者的角度出发一步一步推出这玩意儿来,但是十分抱歉我实在是搞不明白他当时的脑回路qwq)

对于第一步,根据前面的定理,如果在\([1, p]\)内随机,每次有\(\frac{1}{p}*\frac{p-1}{2}\)的概率找到一个解,那么期望步数大约为两次,因此复杂度是可以保证的。

但是找到这个东西有什么用呢?。如果我们把之前的数域记做\(\mathbf F_p\),\(\omega\)在这个数域下是不能开根的,但是我们可以构造一个新的数域\(\mathbf F_p\),使得\(\omega\)在\(\mathbf F_{p2}\)下能够开根。类比于\(-1\)在复数域下能够表示为\(\sqrt{-1}\)一样。

这样的话\(\mathbf F_{p2}\)内的数都可以写作\(a + k\omega\)的形式。可以证明这玩意儿确实是个合法的域,证明过程,同时也可以证明在\(\mathbf F_{p2}\)下得到的解在\(\mathbf F_{p1}\)下也成立,同时最后的答案中\(\omega\)的系数一定为\(0\)

现在来简单说明一下为什么\(x \equiv (a+\omega)^{\frac{p+1}{2}}\)

先来了解两个性质

  • \(\omega^p \equiv -\omega \pmod p\)

证明:

\[\begin{aligned}
\omega^p &= (a^2-n)^{\frac{p}{2}}\\
&= (a^2 - n)^{\frac{p - 1}{2}} (a^2 - n)^{\frac{1}{2}}\\
&= -\omega
\end{aligned}
\]

  • \((a + b)^p \equiv a^p + b^p \pmod p\)

证明就直接考虑二项式定理中的组合数展开,发现除了第一项和最后一项之外都无法把\(n!\)消掉。

那么要证明\(x \equiv (a+\omega)^{\frac{p+1}{2}}\),实际上我们只需要证明\((a+\omega)^{p+1}\equiv n \pmod p\)就行了

\[\begin{aligned}
&(a + \omega)^{p + 1}\\
=&(a + \omega)^p(a + \omega)\\
=&(a - \omega)(a + \omega)(\text{根据费马小定理$a^p \equiv p \pmod p$})\\
=&(a^2 - \omega^2)\\
=&(a^2 - (a^2 - n))\\
=&n
\end{aligned}
\]

算法的大概思想就讲完了,下面煮个栗子~。

对于\(x^2 \equiv n \pmod p\)

假设此时\(p=13, n = 10\)。

首先要找到一个\(a\)满足\((\frac{a^ - 10}{13}) = -1\),然后脸黑的attack在经过1e9 +7次尝试后终于找到了一个\(a =2\)它满足条件,因为\((\frac{7}{13}) = -1\)此时\(\omega = \sqrt{a^2 - n} = \sqrt{-6}\)

按照老祖宗讲给我们的

\(x \equiv (2 + \sqrt{-6})^{7} \pmod {13}\)

\[\begin{aligned}
&\left(2+{\sqrt {-6}}\right)^{2}=4+4{\sqrt {-6}}-6=-2+4{\sqrt {-6}}\\
&\left(2+{\sqrt {-6}}\right)^{4}=\left(-2+4{\sqrt {-6}}\right)^{2}=-1-3{\sqrt {-6}}\\
&\left(2+{\sqrt {-6}}\right)^{6}=\left(-2+4{\sqrt {-6}}\right)\left(-1-3{\sqrt {-6}}\right)=9+2{\sqrt {-6}}\\
&\left(2+{\sqrt {-6}}\right)^{7}=\left(9+2{\sqrt {-6}}\right)\left(2+{\sqrt {-6}}\right)=6.
\end{aligned}
\]

然后不难发现\(36 \equiv 10 \pmod {13}\)

同时因为平方的性质,\(-x\)也是一个合法解,因此\(-6 + 13 = 7\)也是合法的

最后有一个小问题就是为什么最后\(\omega\)的系数一定是\(0\),参考资料中给出的解释我实在是不能理解,如果有看得懂的大佬欢迎给本菜鸡讲一下qwq

代码模板

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int mod = 13;
  4. namespace TwoRemain {
  5. template <typename A, typename B> inline int add(A x, B y) {if(x + y < 0) return x + y + mod; return x + y >= mod ? x + y - mod : x + y;}
  6. template <typename A, typename B> inline void add2(A &x, B y) {if(x + y < 0) x = x + y + mod; else x = (x + y >= mod ? x + y - mod : x + y);}
  7. template <typename A, typename B> inline int mul(A x, B y) {return 1ll * x * y % mod;}
  8. template <typename A, typename B> inline void mul2(A &x, B y) {x = (1ll * x * y % mod + mod) % mod;}
  9. int fmul(int a, int p, int Mod = mod) {
  10. int base = 0;
  11. while(p) {
  12. if(p & 1) base = (base + a) % Mod;
  13. a = (a + a) % Mod; p >>= 1;
  14. }
  15. return base;
  16. }
  17. int fp(int a, int p, int Mod = mod) {
  18. int base = 1;
  19. while(p) {
  20. if(p & 1) base = fmul(base, a, Mod);
  21. p >>= 1; a = fmul(a, a, Mod);
  22. }
  23. return base;
  24. }
  25. int f(int x) {
  26. return fp(x, (mod - 1) >> 1);
  27. }
  28. struct MyComplex {
  29. int a, b;
  30. int cn;
  31. MyComplex operator * (const MyComplex &rhs) {
  32. return {
  33. add(fmul(a, rhs.a), fmul(cn, fmul(b, rhs.b, mod))),
  34. add(fmul(a, rhs.b), fmul(b, rhs.a)),
  35. cn
  36. };
  37. }
  38. };
  39. MyComplex fp(MyComplex a, int p) {
  40. MyComplex base = {1, 0, a.cn};
  41. while(p) {
  42. if(p & 1) base = base * a;
  43. a = a * a; p >>= 1;
  44. }
  45. return base;
  46. }
  47. int TwoSqrt(int n) {
  48. if(f(n) == mod - 1) return -1;
  49. if(f(n) == 0) return 0;
  50. int a = -1, val = -1;
  51. while(val == -1) {
  52. a = rand() << 15 | rand();
  53. val = add(mul(a, a), -n);
  54. if(f(val) != mod - 1) val = -1;
  55. }
  56. return fp({a, 1, val}, (mod + 1) / 2).a;
  57. }
  58. }
  59. using namespace TwoRemain;
  60. signed main() {
  61. cout << TwoSqrt(10);
  62. return 0;
  63. }

参考资料

二次剩余Cipolla算法学习小记

Legendre symbol

二次剩余Cipolla算法学习笔记的更多相关文章

  1. Cipolla算法学习笔记

    学习了一下1个$\log$的二次剩余.然后来水一篇博客. 当$p$为奇素数的时候,并且$(n, p) \equiv 1 \pmod{p}$,用Cipolla算法求出$x^2 \equiv n \pmo ...

  2. C / C++算法学习笔记(8)-SHELL排序

    原始地址:C / C++算法学习笔记(8)-SHELL排序 基本思想 先取一个小于n的整数d1作为第一个增量(gap),把文件的全部记录分成d1个组.所有距离为dl的倍数的记录放在同一个组中.先在各组 ...

  3. Manacher算法学习笔记 | LeetCode#5

    Manacher算法学习笔记 DECLARATION 引用来源:https://www.cnblogs.com/grandyang/p/4475985.html CONTENT 用途:寻找一个字符串的 ...

  4. Johnson算法学习笔记

    \(Johnson\)算法学习笔记. 在最短路的学习中,我们曾学习了三种最短路的算法,\(Bellman-Ford\)算法及其队列优化\(SPFA\)算法,\(Dijkstra\)算法.这些算法可以快 ...

  5. 某科学的PID算法学习笔记

    最近,在某社团的要求下,自学了PID算法.学完后,深切地感受到PID算法之强大.PID算法应用广泛,比如加热器.平衡车.无人机等等,是自动控制理论中比较容易理解但十分重要的算法. 下面是博主学习过程中 ...

  6. Johnson 全源最短路径算法学习笔记

    Johnson 全源最短路径算法学习笔记 如果你希望得到带互动的极简文字体验,请点这里 我们来学习johnson Johnson 算法是一种在边加权有向图中找到所有顶点对之间最短路径的方法.它允许一些 ...

  7. Cipolla算法学习小记

    转自:http://blog.csdn.net/doyouseeman/article/details/52033204 简介 Cipolla算法是解决二次剩余强有力的工具,一个脑洞大开的算法. 认真 ...

  8. 算法学习笔记——sort 和 qsort 提供的快速排序

    这里存放的是笔者在学习算法和数据结构时相关的学习笔记,记录了笔者通过网络和书籍资料中学习到的知识点和技巧,在供自己学习和反思的同时为有需要的人提供一定的思路和帮助. 从排序开始 基本的排序算法包括冒泡 ...

  9. R语言实现关联规则与推荐算法(学习笔记)

    R语言实现关联规则 笔者前言:以前在网上遇到很多很好的关联规则的案例,最近看到一个更好的,于是便学习一下,写个学习笔记. 1 1 0 0 2 1 1 0 0 3 1 1 0 1 4 0 0 0 0 5 ...

随机推荐

  1. [编译] 5、在Linux下搭建安卓APP的开发烧写环境(makefile版)—— 在Linux上用命令行+VIM开发安卓APP

    星期三, 19. 九月 2018 02:19上午 - BEAUTIFULZZZZ 0)前言 本文不讨论用IDE和文本编辑器开发的优劣,是基于以下两点考虑去尝试用命令行编译安卓APP的: 了解安卓APP ...

  2. 1.9 From Native to HTML5

    The mobile technology has become more and more mature, and it has evolved from a ridiculous situatio ...

  3. touchweb网站常见问题,手机网站注意问题

    一.h5网站input 设置为type=number的问题 h5网页input 的type设置为number一般会产生三个问题,一个问题是maxlength属性不好用了.另外一个是form提交的时候, ...

  4. Java中,多态的实现有哪些要求?实现多态的关键技术?

     多态指的是允许不同类的对象对同一消息做出响应,即同一消息可以根据发送对象的不同而采用多种不同的行为方式(发送消息就是函数调用).实现多态的方法是动态绑定( Dynamic Binding),动态绑定 ...

  5. js 操作本地sqlite

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  6. [Swift]LeetCode216. 组合总和 III | Combination Sum III

    Find all possible combinations of k numbers that add up to a number n, given that only numbers from ...

  7. 解决Xftp连接不上Linux虚拟机问题。

    首先 打开cmd窗口 ping一下 虚拟机的ip 这样证明是可以连接的,如果不可以就是你ip地址这块的问题. 可以之后打开Xftp新建 ,把默认的FTP改成SFTP.

  8. 『追捕盗贼 Tarjan算法』

    追捕盗贼(COCI2007) Description 为了帮助警察抓住在逃的罪犯,你发明了一个新的计算机系统.警察控制的区域有N个城市,城市之间有E条双向边连接,城市编号为1到N. 警察经常想在罪犯从 ...

  9. Unity资源打包学习笔记(一)、详解AssetBundle的流程

    转载请标明出处:http://www.cnblogs.com/zblade/ 本文参照unity官网上对于assetBundle的一系列讲解,主要针对assetbundle的知识点做一个梳理笔记,也为 ...

  10. 理解和使用Promise.all和Promise.race

    一.Pomise.all的使用 Promise.all可以将多个Promise实例包装成一个新的Promise实例.同时,成功和失败的返回值是不同的,成功的时候返回的是一个结果数组,而失败的时候则返回 ...