大步小步走算法处理这样的问题:

A^x = B (mod C)

求满足条件的最小的x(可能无解)

其中,A/B/C都可以是很大的数(long long以内)

 

先分类考虑一下:

当(A,C)==1 即A、C互质的时候,

叫他BSGS:

A一定存在mod C意义下的逆元,所以,A^k也存在。

注意到,A^(fai(c)) = 1 (mod c)  ......................(fai(c)表示c的欧拉函数值)

所以,A^(fai(c)+1) = A (mod C) 就重新回去了。

所以,最小的x值,如果有解,必然小于等于fai(c)

枚举显然是不可靠的。

这样考虑:将对数值分解:x=x1+x2;

将A^(0~sqrt(fai(c)) mod C 算出来,加入到一个hash表中,

这样,A^x=A^(x1+x2) 让 x1 取成:0*sqrt(fai(c) ,1*(sqrt(fai(c)) ,2*(sqrt(fai(c)) ... fai(c)

A^(p*sqrt(fai(c))+x2) = B mod C

因为,A^k都存在逆元,所以可以直接把A^(sqrt(fai(c))逆元预处理出来,再在每次循环p的时候,把A^(p*sqrt(fai(c))除过去;

即:A^x2 = B*ni mod C

对于这个B*ni(取模后),只需要在之前处理的hash表中查一下有没有出现就可以、

出现了就对应一个x2,对于x ,就是p*sqrt(fai(c))+x2

否则继续循环p

为了保证这个x是最小的x,

我们在建hash表的时候,是x的值从小到大建,如果这个值之前没有出现,就插入,否则不进行操作(相当于用小的x覆盖大的)

②我们分块的时候,从小到大枚举p,所以找到的第一个就是答案。

如果一直没有找到,就返回无解。

复杂度:O(sqrt(c)) (哈希表用邻接表挂链实现,不用map的log复杂度)

BSGS代码:poj2417(这个保证了模数是质数(直接用的费马),但是其实不一定是)

#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<cstring>
using namespace std;
typedef long long ll;
const int N=46349;
const int mod=100003;
ll p,A,B;
ll ni[N];
struct node{
    int nxt[mod],val[mod],id[mod],cnt;
    int hd[mod];
    void init(){
        memset(nxt,0,sizeof nxt),memset(val,0,sizeof val);cnt=0;
        memset(hd,0,sizeof hd);memset(id,0,sizeof id);
    }
    void insert(ll x,int d){
        int st=x%mod;
        for(int i=hd[st];i;i=nxt[i]){
            if(val[i]==x) return;
        }
        val[++cnt]=x;nxt[cnt]=hd[st];id[cnt]=d;hd[st]=cnt;
    }
    int find(ll x){
        int st=x%mod;
        for(int i=hd[st];i;i=nxt[i]){
            if(val[i]==x) return id[i];
        }
        return -233;
    }
}ha;
map<ll,int>mp;
ll qm(ll a,ll b){
    ll ret=1,base=a;
    while(b){
        if(b&1) ret=(ret*base)%p;
        base=(base*base)%p;
        b>>=1;
    }
    return ret;
}
ll BSGS(){
    ll up=(ll)floor(sqrt(1.0*p-1))+1;
    cout<<up<<endl;
    ni[0]=1;
    for(int i=1;i<=up;i++){
        ni[i]=qm(qm(A,i*up),p-2);
    }
    for(int i=0;i<up;i++){
        ll t=qm(A,i);
        ha.insert(t,i);
    }
    for(int i=0;i<=up;i++){
        if(i*up>p-1) break;
        ll ri=B*ni[i]%p;
        ll ret=ha.find(ri);
        if(ret>=0) return i*up+ret;
    }
    return -233;
}
int main()
{
    while(scanf("%lld",&p)!=EOF){
        scanf("%lld%lld",&A,&B);
        ha.init();
        ll ret=BSGS();
        if(ret==-233){
            puts("no solution");
        }
        else{
            printf("%lld\n",ret);
        }
    }
    return 0;
}
BSGS

相关文章: