• 二次剩余【模下开方】奇波拉算法


    奇波拉算法只适合模数为奇质数的情况

    本博客仅提供主干结论和步骤,无繁琐证明

    只需掌握  1欧拉判别准则 2重载复数域 3快速幂 4随机数  即可

    详细证明链接登录 - 洛谷

    欧拉判别准则

    判断一个数n是否为模数p的二次剩余(是否能在模p意义下开方)

    根据费马小定理

    勒德让函数

    随机找一个数a, 计算a^2-n函数值。直到勒德让函数值为-1,否则一直寻找。

    这里有一个定理为使得勒德让函数为-1的a期望为2,也就是我们平均找两次随机数就够了

    重载复数域

    复数域中,有一个i,i^2=1。这里我们重新创建一个负数域,令 i^2=  a^2-n

    1. inline complex operator * (complex x, complex y)
    2. {
    3. return complex((x.real * y.real + II* x.imag % mod * y.imag) % mod,
    4. (x.imag * y.real + x.real * y.imag) % mod);
    5. }

     其中II指的是i^2,和复数运算一样,只不过把-1换成了II

    然后我们这样做的好处是,再写复数时,虚部只需要写系数就够了

    最终答案是

    也就是计算复数快速幂  (a,1) 1代表i的系数

    最终虚数部系数一定为0,所以可以直接输出实部

    1. # include
    2. using namespace std;
    3. typedef long long int ll;
    4. ll II,mod;
    5. struct cp
    6. {
    7. ll real,imag;
    8. };
    9. cp operator *(cp x,cp y)
    10. {
    11. cp z;
    12. z.real=(x.real*y.real%mod+II*x.imag%mod*y.imag%mod)%mod;
    13. z.imag=(x.real*y.imag%mod+x.imag*y.real%mod)%mod;
    14. return z;
    15. }
    16. ll qp(ll base, ll pow)
    17. {
    18. ll ans=1ll;
    19. while(pow)
    20. {
    21. if(pow&1)
    22. ans=ans*base%mod;
    23. base=base*base%mod;
    24. pow>>=1;
    25. }
    26. return ans;
    27. }
    28. bool check(ll x, ll y)
    29. {
    30. return qp(x,y)==1;
    31. }
    32. void getans(cp base,ll pow,ll &x1,ll&x2)
    33. {
    34. cp ans;
    35. ans.real=1ll;
    36. ans.imag=0;
    37. while(pow)
    38. {
    39. if(pow&1)
    40. ans=ans*base;
    41. pow>>=1;
    42. base=base*base;
    43. }
    44. x1=ans.real;
    45. x2=(mod-x1)%mod;
    46. }
    47. int main ()
    48. {
    49. int t;
    50. cin>>t;
    51. while(t--)
    52. {
    53. ll n;
    54. cin>>n;
    55. cin>>mod;
    56. if(!n)
    57. {
    58. cout<<0<<'\n';
    59. continue;
    60. }
    61. if(!check(n,(mod-1)/2))
    62. {
    63. cout<<"Hola!"<<'\n';
    64. continue;
    65. }
    66. ll a=rand()%mod;
    67. while(!a || check((a*a-n+mod)%mod,(mod-1)/2))
    68. a=rand()%mod;
    69. II=(a*a+ mod-n )%mod;
    70. ll x1,x2;
    71. cp now;
    72. now.real=a;
    73. now.imag=1ll;
    74. getans(now,(mod+1)/2,x1,x2);
    75. if(x1!=x2)
    76. {
    77. cout<" "<'\n';
    78. }
    79. else
    80. {
    81. cout<'\n';
    82. }
    83. }
    84. return 0;
    85. }

  • 相关阅读:
    Java中如何计算一个HashSet对象的大小呢?
    开发手机软件需要学什么内容才可以呢
    【AGC】调测应用内消息服务的收不到弹窗的问题
    Spring Boot + Canal 实现数据库实时监控
    DNS协议隧道(2)
    删除变量为什么需要del加gc.collect
    基于springboot+vue的大学生创新创业系统(前后端分离)
    最新ChatGPT商业运营系统源码+支持GPT4/支持ai绘画+支持Midjourney绘画
    【BOOST C++】win10下,用VS2019开发BOOST C++代码
    OFD文件打开教程
  • 原文地址:https://blog.csdn.net/jisuanji2606414/article/details/126058596