BSGS and extended BSGS

Keywords: Algorithm number theory

summary

It is mainly used to solve the an=b(mod p) problem and solve the minimum non negative integer n to satisfy the left formula. Ordinary BSGS can solve the case of a and P coprime, and extended BSGS can solve the case of non coprime

Common BSGS

Problem solving steps

1. Take m=ceil(sqrt §) (rounded up). If the solution exists, let n=im-j, that is, the number pair (i,j) exists
2.an = b ( mod p )aim-j = b( mod p )aim = baj ( mod p )
3. Enumerate the values of baj in the range of 0-m and store j in the hash table
4. Enumerate the value of aim in the range of 1-m and look it up in the hash table. If it is found, i*m-j will be output. Otherwise, there is no answer

Code template

1.	#include<bits/stdc++.h>  
2.	#define int long long  
3.	using namespace std;  
4.	int a,p,b;  
5.	unordered_map<int,int> mp;  
6.	int qpow(int a,int n,int mod)  
7.	{  
8.	    int ans=1;  
9.	    while(n)  
10.	    {  
11.	        if(n&1) ans=ans*a%mod;  
12.	        a=a*a%mod;  
13.	        n>>=1;  
14.	    }  
15.	    return ans;  
16.	}  
17.	int bsgs(int a,int b,int p)  
18.	{  
19.	    a%=p;  
20.	    b%=p;  
21.	    if(1==b%p) return 0;  //The special judgment result is 0
22.	    int m=ceil(sqrt(p));  
23.	    int baj=1;  
24.	    for(int i=0;i<=m;i++)  
25.	    {  
26.	        if(i==0)  
27.	        {  
28.	            baj=b%p;  
29.	            mp[baj]=i;  
30.	            continue;  
31.	        }  
32.	        baj*=a;  
33.	        baj%=p;  
34.	        mp[baj]=i;  
35.	    }  
36.	    int am=qpow(a,m,p);  
37.	    int tmp=1;  
38.	    for(int i=1;i<=m;i++)//Since n is assumed to be i*m-j, if i enumerates from 0, it is possible to output negative numbers  
39.	    {  
40.	        tmp*=am;  
41.	        tmp%=p;  
42.	        if(mp.count(tmp)) return i*m-mp[tmp];  
43.	    }  
44.	    return -1;  
45.	}  
46.	signed main()  
47.	{  
48.	    cin.tie(0);  
49.	    cout.tie(0);  
50.	    ios::sync_with_stdio(0);  
51.	    while(cin>>a>>p>>b)  
52.	    {  
53.	        mp.clear();  
54.	        if(a==0&&p==0&&b==0) break;  
55.	        int ans=bsgs(a,b,p);  
56.	        if(ans==-1) cout<<"No Solution"<<endl;  
57.	        else cout<<ans<<endl;  
58.	    }  
59.	    return 0;  
60.	}  

Extended BSGS

Problem solving steps

1. When a and p are coprime, ordinary BSGS can be applied
2. When a and P are not coprime, let gcd be the greatest common divisor of a and P. for the equation an = b (mod p), there must be a / gcd * an-1 = b / gcd (mod p / gcd). Therefore, if b is not a multiple of gcd, the equation has no solution
3. For the new equation, let b / GCD / (A / GCD) = b ', p/gcd = p', use the inverse element to deal with b ', and solve it recursively

Code template

1.	#include<bits/stdc++.h>  
2.	using namespace std;  
3.	#define int long long  
4.	const int inf=1e8;  
5.	int a,p,b,x,y;  
6.	int qpow(int a,int n,int mod)  
7.	{  
8.	    int ans=1;  
9.	    while(n)  
10.	    {  
11.	        if(n&1) ans=ans*a%mod;  
12.	        a=a*a%mod;  
13.	        n>>=1;  
14.	    }  
15.	    return ans;  
16.	}  
17.	int exgcd(int a,int b,int &x,int &y)  
18.	{  
19.	    if(!b)  
20.	    {  
21.	        x=1;  
22.	        y=0;  
23.	        return a;  
24.	    }  
25.	    int ans=exgcd(b,a%b,x,y);  
26.	    int tmp=x;  
27.	    x=y;  
28.	    y=tmp-(a/b)*y;  
29.	    return ans;  
30.	}  
31.	unordered_map<int,int> mp;  
32.	int bsgs(int a,int b,int p)  
33.	{  
34.	    mp.clear();  
35.	    a=a%p;  
36.	    //b=(b%p+p)%p;  
37.	    if(1%p==b%p) return 0;//The special judgment result is 0  
38.	    int m=ceil(sqrt(p));  
39.	    int baj=1;  
40.	    for(int i=0;i<=m;i++)  
41.	    {  
42.	        if(i==0)  
43.	        {  
44.	            baj=b%p;  
45.	            mp[baj]=i;  
46.	            continue;  
47.	        }  
48.	        baj*=a;  
49.	        baj%=p;  
50.	        mp[baj]=i;  
51.	    }  
52.	    int am=qpow(a,m,p);  
53.	    int tmp=1;  
54.	    for(int i=1;i<=m;i++)  
55.	    {  
56.	        tmp*=am;  
57.	        tmp%=p;  
58.	        if(mp.count(tmp)) return i*m-mp[tmp];  
59.	    }  
60.	    return -1;  
61.	}  
62.	int exbsgs(int a,int b,int p)  
63.	{  
64.	    b=(b%p+p)%p;  //Make b positive
65.	    if(1%p==b%p) return 0;  
66.	    int gcd=exgcd(a,p,x,y);  
67.	    if(gcd>1)  
68.	    {  
69.	        if(b%gcd) return -inf;  
70.	        exgcd(a/gcd,p/gcd,x,y);  
71.	        int a2=a;  
72.	        int b2=b/gcd*x%(p/gcd);  
73.	        int p2=p/gcd;  
74.	        return exbsgs(a2,b2,p2)+1;  
75.	    }  
76.	    return bsgs(a,b,p);  
77.	}  
78.	signed main()  
79.	{  
80.	    ios::sync_with_stdio(0);  
81.	    while(cin>>a>>p>>b)  
82.	    {  
83.	        if(!a&&!b&&!p) break;  
84.	        int ans=exbsgs(a,b,p);  
85.	        if(ans<0) cout<<"No Solution"<<endl;  
86.	        else cout<<ans<<endl;  
87.	    }  
88.	    return 0;  
89.	}  

Classic examples

Rogue P4861 button

Topic entry

Title Description
Ada was locked up in a room. There is a button on the iron door of the room, and a display shows "1".
Next to it is a small line of words: "this is a high-precision M-ary calculator. Every time you press the button, the number on the screen will be multiplied by K. when the single digit becomes 1 again, the door will open."
Ada is eager to go out, so you have to find out her minimum number of keystrokes within 1s.

Input format
One line, two integers m and k
Output format
One number per line indicates the minimum number of keystrokes.
If Ada cannot open the door no matter how many times he presses, output "Let's go Blue Jays!" (without quotation marks).
Input sample 1
11 2
Output sample 1
10
Input sample 2
6 26
Output sample 2
Let's go Blue Jays!

thinking
If the final answer exists, there are two expressions, kn and m*x+1, so you can list the equation, kn = 1 (MOD m). Since the answer cannot be 0, you can judge the output of 0 in the original template

code

1.	#include<bits/stdc++.h>  
2.	using namespace std;  
3.	#define int long long  
4.	int m,k;  
5.	unordered_map<int,int> mp;  
6.	int exgcd(int a,int b,int &x,int &y)  
7.	{  
8.	    if(b==0)  
9.	    {  
10.	        x=1;  
11.	        y=0;  
12.	        return a;  
13.	    }  
14.	    int ans=exgcd(b,a%b,x,y);  
15.	    int tmp=x;  
16.	    x=y;  
17.	    y=tmp-(a/b)*y;  
18.	    return ans;  
19.	}  
20.	int qpow(int a,int n,int mod)  
21.	{  
22.	    int ans=1;  
23.	    while(n)  
24.	    {  
25.	        if(n&1) ans=ans%mod*a%mod;  
26.	        a=a%mod*a%mod;  
27.	        n>>=1;  
28.	    }  
29.	    return ans;  
30.	}  
31.	int bsgs(int a,int b,int p)  
32.	{  
33.	    a%=p;  
34.	    b%=p;  
35.	    int m=ceil(sqrt(p));  
36.	    int tmp;  
37.	    for(int i=0;i<=m;i++)  
38.	    {  
39.	        if(i==0)  
40.	        {  
41.	            tmp=b%p;  
42.	            mp[tmp]=i;  
43.	            continue;  
44.	        }  
45.	        tmp*=a;  
46.	        tmp%=p;  
47.	        mp[tmp]=i;  
48.	    }  
49.	    int am=qpow(a,m,p);  
50.	    int now=1;  
51.	    for(int i=1;i<=m;i++)  
52.	    {  
53.	        now*=am;  
54.	        now%=p;  
55.	        //cout<<"now="<<now<<endl;  
56.	        if(mp.count(now)&&i*m-mp[now]==0) continue;  //The special judgment result is 0
57.	        else if(mp.count(now)) return i*m-mp[now];  
58.	    }  
59.	    return -1;  
60.	}  
61.	int x,y;  
62.	signed main()  
63.	{  
64.	    cin>>m>>k;  
65.	    int gcd=exgcd(m,k,x,y);  
66.	    if(gcd!=1)  
67.	    {  
68.	        cout<<"Let's go Blue Jays!"<<endl;  
69.	        return 0;  
70.	    }  
71.	    int ans=bsgs(k,1,m);  
72.	    if(ans==-1) cout<<"Let's go Blue Jays!"<<endl;  
73.	    else cout<<ans<<endl;  
74.	    return 0;  
75.	}  

Posted by EZE on Sat, 25 Sep 2021 22:11:21 -0700