数论——Baby Step Giant Step及扩展算法

来源:互联网 发布:淘宝网络环境异常 编辑:程序博客网 时间:2024/05/21 06:24

bsgs算法

Baby Step Giant Step算法,简称BSGS算法,也称为大步小步算法.

解决对象

离散对数:当xGk(modm)时,logG(x)k(modϕ(m))。此处的logG(x)x以整数G为底,模ϕ(m)的离散对数。
BSGS算法就是用来求解AxB(modC)。原始的BSGS算法只能解决C是质数的问题。

求解步骤

m=C向上取整,x=i×m+j,那么,Ax=(Am)i×Aj,0i<m,0j<m。然后可以枚举i,这是一个O(C)级别的枚举。
对于枚举的每一个i,都令D=(Am)i,令E=Aj,那么就有D×EB(modC)。然后用扩展欧几里得求解。
不过还应该特判AC的倍数的情况,比较容易。
对于多次调用Aj的情况,不用每次都用快速幂,只需要扔进hash表就可以了。

基本代码

这是我的code:

如果感觉不顺手,请看下面:
总有一款板子适合你!
来自这里

#include<iostream>    #include<cstdio>    #include<cstring>    #include<algorithm>    #include<map>    #include<cmath>     using namespace std;    long long a,b,c,m,f[10000000];    map<long long,int> mp;    long long  qsm(long long x)  //快速幂  {      long long sum=1; long long aa=a;       while (x>0)       {         if (x&1)          sum=(sum*aa)%c;         x=x>>1;         aa=(aa*aa)%c;       }      return sum;    }    int main()    {      mp.clear();       while (scanf("%lld%lld%lld",&c,&a,&b)!=EOF)       {       mp.clear();         if (a%c==0)   //判断a,c 是否互质,因为c 是质数,所以直接判断是否整除即可       {            printf("no solution\n");            continue;         }         int p=false;         m=ceil(sqrt(c));        long long ans;         for (int i=0;i<=m;i++)          {            if (i==0)            {              ans=b%c; mp[ans]=i; continue;            }           ans=(ans*a)%c;               mp[ans]=i;          }        long long t=qsm(m); ans=1;       for (int i=1;i<=m;i++)          {            ans=(ans*t)%c;            if (mp[ans])             {                int t=i*m-mp[ans];                printf("%d\n",(t%c+c)%c);                p=true;                break;             }          }         if (!p)           printf("no solution\n");       }    }    

来自这里

LL BSGS(LL y,LL z,LL p){    map<LL,LL> ma;    LL m=sqrt(p),tmp=0;    ma.clear();    if(y%p==0&&z==0) return 1;    if(y%p==0&&z!=0) return -1;    for(int i=0;i<=m;i++)    {        if(!i) {tmp=z%p;ma[tmp]=i;continue;}        tmp=(tmp*y)%p;        ma[tmp]=i;    }    tmp=1;LL t=power(y,m,p);    for(int i=1;i*i<=p;i++)    {        tmp=(tmp*t)%p;        if(ma[tmp])        {            LL ans=i*m-ma[tmp];            return ans;        }    }    return -1;}

SDOI2011 计算器

题目描述

你被要求设计一个计算器完成以下三项任务:
1、给定y、z、p,计算y^z mod p 的值;
2、给定y、z、p,计算满足xy ≡z(mod p)的最小非负整数x;
3、给定y、z、p,计算满足y^x ≡z(mod p)的最小非负整数x。
为了拿到奖品,全力以赴吧!

输入输出格式

输入格式:

输入文件calc.in 包含多组数据。
第一行包含两个正整数T、L,分别表示数据组数和询问类型(对于一个测试点内的所有数
据,询问类型相同)。
以下T 行每行包含三个正整数y、z、p,描述一个询问。

输出格式:

输出文件calc.out 包括T 行.
对于每个询问,输出一行答案。
对于询问类型2 和3,如果不存在满足条件的,则输出“Orz, I cannot find x!”。

输入输出样例

输入样例#1:

3 1
2 1 3
2 2 3
2 3 3

输出样例#1:

2
1
2

输入样例#2:

3 2
2 1 3
2 2 3
2 3 3

输出样例#2:

2
1
0

输入样例#3:

4 3
2 1 3
2 2 3
2 3 3
2 4 3

输出样例#3:

0
1
Orz, I cannot find x!
0

数据规模和约定

20% K=1,35% K=2,45% K=3。100% 1<=y,z,P<=10^9,P为质数,1<=T<=10

题解

这里有三种问法,第一种问法就直接是带模的快速幂,没啥好说的。
第二种问法就是求线性方程解,那就用扩展欧几里得!
第三种问法就是本文考虑的BSGS算法,也就是一个板子题目吧。怎么写板子前面已经介绍过了。

code

原创粉丝点击