数论——Baby Step Giant Step大步小步算法

25 篇文章 2 订阅
16 篇文章 9 订阅

bsgs算法

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

解决对象

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

求解步骤

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

基本代码(用map模拟hash)

这道题
采用map,代码量比hash少的多了!!
(hash我调了好几天没调出来,后来换成map就过了,肯定是hash写错了)

#include<bits/stdc++.h>
using namespace std;
inline long long read()
{
    long long num=0;
    char c=' ';
    bool flag=true;
    for(;c>'9'||c<'0';c=getchar())
    if(c=='-')
    flag=false;
    for(;c>='0'&&c<='9';num=num*10+c-48,c=getchar());
    return flag ? num : -num;
}
int A,B,C;
namespace ksm
{
    long long qpow(long long a,long long t,long long p)
    {
        int base=a%p;
        long long ans=1;
        while(t)
        {
            if(t&1)
            ans=(long long)ans%p*(base%p)%p;
            base=(long long)base%p*(base%p)%p;
            t>>=1;
        }
        return ans;
    }
}


namespace BSGS
{
    map<long long,int>mp;
    int bsgs(int A,int B,int C)
    {
        mp.clear();
        if(A%C==0)
        return -1;
        int p=false;
        int m=ceil(sqrt(C));
        long long ans;
        for(int i=0;i<=m;i++)
        {
            if(!i)
            {
                ans=B%C;
                mp[ans]=i;
                continue;
            }
            ans=ans*A%C;
            mp[ans]=i;
        }
        long long t=ksm::qpow(A,m,C);ans=1;
        for(int i=1;i<=m;i++)
        {
            ans=(ans*t)%C;
            if(mp[ans])
            {
                int t=i*m-mp[ans];
                return (t%C+C)%C;
                p=true;
                break;
            }
        }
        if(!p)return -1;

    }
}

int main()
{
    int t=read();
    int l=read();
    if(l==1)
    {
        using namespace ksm;
        while(t--)
        {
            int a=read();
            int c=read();
            int b=read();
            printf("%lld\n",qpow(a,c,b));
        }
        return 0;
    }
    if(l==2)
    {
        using namespace ksm;
        while(t--)
        {
            int y=read();
            int z=read();
            int p=read();
            int gcd=__gcd(y,p);
            if(z%gcd)
            {
                printf("Orz, I cannot find x!\n");
                continue;
            }
            printf("%d\n",((z%p)*(long long)qpow(y,p-2,p))%p);
        }
    }
    if(l==3)
    {
        using namespace BSGS;
        using namespace ksm;
        while(t--)
        {
            A=read();B=read();C=read();
            long long ans=bsgs(A,B,C); 
            if(ans==-1)
            {
                printf("Orz, I cannot find x!\n");
                continue;
            }
            printf("%lld\n",ans);
        }
    }
    return 0;
}

鸣谢这位大佬map的启示!
我是传送门

SDOI2011 计算器

题目描述

你被要求设计一个计算器完成以下三项任务:
1、给定y、z、p,计算 yzmodp y z m o d p 的值;
2、给定y、z、p,计算满足 xyz x y ≡ z (mod p)的最小非负整数x;
3、给定y、z、p,计算满足 yxz(mod p) y x ≡ z ( m o d   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

就是纯板子吧,直接照搬上面的代码就行了。

扩展BSGS

传统的bsgs只能解决c是质数的问题,如果c是合数,那就需要使用扩展bsgs。因为不是质数,所以不能直接求逆元。
扩展BSGS大概有那么几几个步骤:
d=gcd(A,C) d = g c d ( A , C ) ,那么 A,B,C A , B , C 可以表示为 A=ad,B=bd A = a ∗ d , B = b ∗ d (如果B不是d的倍数且 B!=1 B ! = 1 则显然无解), C=cd C = c ∗ d 。代入原式可得 a×(a×d)x1b(modc) a × ( a × d ) x − 1 ≡ b ( mod c ) ,如果我们把 D×a D × a ,那么左边就只剩下 (a×d)x1 ( a × d ) x − 1 了 ,不停地求 d=gcd(A,C) d = g c d ( A , C ) ,然后将B和C分别除以d。D要乘A/d,num++,直到d=1为止。
最后方程就成为这种形式了: D×AxnumB(modC) D × A x − n u m ≡ B ( mod C ) 。那么令 x=i×m+j+num x = i × m + j + n u m ,那么原先的BSGS一样处理就可以了。但是需要注意的是,x

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值