zoukankan      html  css  js  c++  java
  • [BSGS]

    [模板] 大步小步算法——BSGS算法

    这个算法叫做B(拔)S(山)G(盖)S(世),或B(北)S(上)G(广)S(深)。 就是这么个骚东西。

    大步小步算法用于解决:已知A, B, C,求X使得
    A^x = B (mod C)
    成立。


    先令 x = i*m-j,其中 m=ceil(sqrt(p)),ceil是向上取整。

    这样原式就变为    ai*m-j = b (mod p),

    移项就变成了      ai*m = b*a(mod p)

    枚举j (范围0-m) ,将 b*aj  存入hash表。

    枚举i (范围1-m) ,从hash表中寻找第一个满足ai*m = b*aj  (mod p)。

    此时   x = i*m-j  就是所要求的。


    那么为什么只计算到 m=ceil(sqrt(q))  就可以确定答案呢?

    因为 x = i*m-j , 所以x 的最大值不会超过p

    由费马小定理知: 当p为质数且 (a,p1 时 ap-1 ≡ (mod p)

    所以 当 x = p-1 时 ap-1 ≡ 1 会重新开始循环 所以 x 最大不会超过 p-1

    所以:如果枚举 x 的话枚举到 p 即可。

    所以使 imj<=p , 即 m=⌈√p⌉ , i,j 最大值也为m。

    还有 我不保证 我写的 不会 出错(逃

     1 #include <cstdio>
     2 #include <iostream>
     3 #include <cmath>
     4 #include <map>
     5 #include <algorithm>
     6 
     7 using namespace std;
     8 
     9 map<long long,long long> kkk;
    10 
    11 int a,b,p,res;
    12 
    13 bool flag;
    14 
    15 long long GCD(long long a,long long b)
    16 {
    17     return !b ? a : GCD(b,a % b); 
    18 } 
    19 
    20 long long quickpower(long long a,long long b,long long p)
    21 {
    22     long long ans = 1;
    23     
    24     while(b)
    25     {
    26         if(b & 1) ans = ans * a % p;
    27         
    28         a *= a;
    29         b >>= 1; 
    30     }
    31     
    32     return ans % p;
    33 }
    34 
    35 int main()
    36 {
    37     while(scanf("%d%d%d",&a,&p,&b) && a != 0 && b != 0 && p != 0)
    38     {
    39         flag = 0;// 判断的 
    40         
    41         if(a == b)// 特判 
    42         {
    43             printf("1
    ");
    44             
    45             flag = 1;
    46         }
    47         
    48         kkk.clear();//清空 
    49         
    50         if(GCD(a,p) != 1)// 不互质 
    51         {
    52             printf("No Solution
    ");
    53             
    54             continue;
    55         }
    56         
    57         int sq = ceil(sqrt(p));// 分块 
    58         
    59         int now = b % p;// j == 0;
    60         
    61         kkk[now] = 0;
    62         
    63         for(int j=1;j<=sq;j++)
    64         {
    65             now = now * a % p;
    66             
    67             kkk[now] = j;
    68         }
    69         
    70         now = 1;
    71         
    72         int power = quickpower(a,sq,p);//求 a^sq 
    73         
    74         for(int i=1;i<=sq;i++)
    75         {
    76             now = now * power % p;// 枚举 a^(i*sq) 
    77             
    78             if(kkk[now] && !flag)// flag 防止 多输出 , 如果找到了重复的 说明已经找到了 
    79             {
    80                 res = i * sq - kkk[now];
    81                 
    82                 printf("%d
    ",(res + p) % p);// 保证不为负数 
    83                 
    84                 flag = 1;
    85                 
    86             }
    87         }
    88         
    89         if(!flag)
    90             printf("No Solution
    ");
    91     }
    92     
    93     return 0;
    94 }
  • 相关阅读:
    golang的server push
    go context学习
    go struct{} 空结构体的特点和作用
    Java基本语法--关键字&标识符
    初识Java
    Dos常用命令
    Markdown进阶教程
    Markdown基础教程
    Navicat Premium15安装与激活
    JDK的安装与环境配置(Windows10)
  • 原文地址:https://www.cnblogs.com/-Wind-/p/10692634.html
Copyright © 2011-2022 走看看