对于a^x≡b(mod p)
保证gcd(a,p)==1,且p为素数
首先我们来回忆一下费马小定理
a^oula(p)=1 (mod p)
p为素数时,oula(p)=p-1,则a^p=a (mod p)
那么我们x枚举到p-1即可
但是p数据量为1e9+7呢?
那么我们就可以引入一个新的算法,bsgs,拔山盖世算法,或者北上广深算法~
算法核心思想是运用分块的思想来降低复杂度,使得原先O(n)->O(sqrt(n))
首先我们设m=(ceil)sqrt(p), //ceil 向上取整
如此a^(i*m-j)=b(modp) 1=<i<=m 0=<j<=m
则转换为a^(i*m)=b*a^j(mod p),
预处理出来所有的b*a^j,然后枚举i即可
Given a prime P, 2 <= P < 2 31, an integer B, 2 <= B < P, and an integer N, 1 <= N < P, compute the discrete logarithm of N, base B, modulo P. That is, find an integer L such that
BL == N (mod P)
Input
Read several lines of input, each containing P,B,N separated by a space.
Output
For each line print the logarithm on a separate line. If there are several, print the smallest; if there is none, print "no solution".
Sample Input
5 2 1
5 2 2
5 2 3
5 2 4
5 3 1
5 3 2
5 3 3
5 3 4
5 4 1
5 4 2
5 4 3
5 4 4
12345701 2 1111111
1111111121 65537 1111111111
Sample Output
0
1
3
2
0
3
1
2
0
no solution
no solution
1
9584351
462803587
Hint
The solution to this problem requires a well known result in number theory that is probably expected of you for Putnam but not ACM competitions. It is Fermat's theorem that states
B(P-1) == 1 (mod P)
for any prime P and some other (fairly rare) numbers known as base-B pseudoprimes. A rarer subset of the base-B pseudoprimes, known as Carmichael numbers, are pseudoprimes for every base between 2 and P-1. A corollary to Fermat's theorem is that for any m
B(-m) == B(P-1-m) (mod P) .
已AC代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
using namespace std;
#define ll long long
const ll INF=1e9+7;
map<ll,ll> mp; //能把一个数组存的数的数量变得很大,远超不同数组
ll qpow(ll a,ll b,ll p) //快速幂取余 求(a^b)mod p
{
ll ans=1;
while(b)
{
if(b%2!=0)
ans=ans*a%p;
a=a*a%p;
b/=2;
}
return ans;
}
int main()
{
ll p,b,n;
while(scanf("%lld%lld%lld",&p,&b,&n)!=EOF)
{
ll m=ceil(sqrt(p)); //ceil向上取整,如ceil根号2等于2
mp.clear(); //mp数组清空
ll ans;
for(ll j=0;j<=m;j++)
{
if(j==0) //如果j==0,b^j=1,所以右边就等于n%p
{
ans=n%p;
mp[ans]=j; //当j==0时,把ans存入mp数组中
continue;
}
ans=(ans*b)%p;
//j!=0时,一步步迭代,ans=(j=(j-1)时的ans)*b%p;
mp[ans]=j; //把ans存入mp数组
}
ll t=qpow(b,m,p); //求a^(im)就是先求出a^m在一个一个求(a^m)^i;
ans=1;
ll flag=0;
for(ll i=1;i<=m;i++)
{
ans=ans*t%p; //一步步迭代i
if(mp[ans]) //如果找到ans,即左右相等,就输出
{
ll wz=i*m-mp[ans]; //wz是自己定义的变量,同题目中的L
printf("%lld\n",(wz%p+p)%p);
flag=1; //如果找到,就让falg=1;没有flag=0;
break;
}
}
if(!flag)
printf("no solution\n");
}
}