题目:POJ 3243 Clever Y (扩展BSGS算法)
题目大意:就是给定a,b,p,让求一个x使得a^xmodp=bmodp。
解题思路:由于数据很大,直接暴力枚举一定超时,由于对p取mod得到的数值是以euler(p)为循环的,这样将原来的式子拆成(a^m)^kmodp=b*a^ymodp,也就是meet in middle,这样只需要枚举到sqrt(p)即可。当然,存的时候有两种存法,一种是map,这个比较慢,还有一个是hash,这个题目运用的就是hash。PS:前段时间因为不懂这个hash(其实就是压缩状态做成一个链表)觉得很不想看这个算法,加上没有题目用得到,也就不了了之了,今天又从新学了一遍,这也就是出来混早晚要还的吧......
ac代码:
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<map>
#define q 100003
using namespace std;
long long point[2*q];
long long next[2*q];
long long val[2*q];
long long pla[2*q];
long long tot;
void add(long long x,long long y){
long long xx=x%q;
next[++tot]=point[xx];
val[tot]=x;
pla[tot]=y;
point[xx]=tot;
}
long long find(long long x){
long long i;
long long xx=x%q;
for (i=point[xx];i;i=next[i]){
if (val[i]==x)return pla[i];
}
return -1;
}
long long gcd(long long a,long long b){
return b==0?a:gcd(b,a%b);
}
long long qpow(long long a,long long b,long long mod){
long long ans;
for (ans=1;b;a=a*a%mod,b>>=1){
if (b&1)ans=ans*a%mod;
}
return ans;
}
long long ebsgs(long long a,long long b,long long p){
long long i;
if (b==1)return 0;
long long t=gcd(a,p),d=1,k=0;
while (t!=1){
if (b%t)return -1;
b/=t;
p/=t;
d=d*(a/t)%p;
k++;
if (b==d)return k;
t=gcd(a,p);
}
memset (point,0,sizeof(point));
memset (next,0,sizeof(next));
tot=0;
long long m=ceil(sqrt(p));
long long am=qpow(a,m,p);
long long mul=b;
add(mul,0);
for (i=1;i<=m;i++){
mul=mul*a%p;
add(mul,i);
}
for (i=1;i<=m+1;i++){
d=d*am%p;
long long place=find(d);
if (place!=-1)return i*m-place+k;
}
return -1;
}
int main(){
long long a,b,p;
while (scanf("%lld%lld%lld",&a,&p,&b)!=EOF&&(a||b||p)){
long long ans=ebsgs(a%p,b%p,p);
if (ans!=-1)printf("%lld\n",ans);
else printf("No Solution\n");
}
}