传送门:poj2417
题解
根据欧拉定理,在模数为p的情况下,正整数b的最小循环节最多为p。
对于p以内,我们当然不能暴力枚举。
那么设
m=p–√
m
=
p
上取整,我们预处理出
n∗b1
n
∗
b
1
到
n∗bm
n
∗
b
m
的值存在hash表里,存的时候若有相同的,就让后面的覆盖前面的就好了(因为我们枚举i*m-j,自然j越大越好,以保证求的的是最小值),然后枚举
i∗m
i
∗
m
(1≤i≤m)
(
1
≤
i
≤
m
)
然后hash表里找对应的值就好了。
最后有可能是个负数,需要取个模。
代码
map版:
#include<cstdio>
#include<iostream>
#include<cmath>
#include<cstring>
#include<map>
using namespace std;
typedef long long ll;
ll mod,b,n,now,bri,ans;
int r;
map<ll,int>mp;
inline ll fp(ll a,int b)
{
ll ret=1;
for(;b;b>>=1,a=a*a%mod) if(b&1) ret=ret*a%mod;
return ret;
}
int main(){
while(scanf("%lld%lld%lld",&mod,&b,&n)==3){
b%=mod;
if(b==0){if(n==1) printf("0\n");else printf("no solution\n");continue;}
mp.clear();
r=(int)(sqrt((double)mod))+1;
now=n%mod;mp[now]=0;
for(int i=1;i<=r;i++) mp[now=(now*b%mod)]=i;
bri=fp(b,r);now=1;int ptr=1;
for(int i=1;i<=r;i++){
now=now*bri%mod;
if(mp[now]){
ptr=0;
ans=r*i-mp[now];
printf("%lld\n",(ans%mod+mod)%mod);
break;
}
}
if(ptr==1) printf("no solution\n");
}
return 0;
}
hash版:
#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
using namespace std;
const int N=2e6+10;
const int hs=63713;
typedef long long ll;
ll mod,b,n,now;int lim;
int head[hs+123],to[N],nxt[N],tot,val[N];
inline void insert(int h,int id){
for(int i=head[h%hs];i;i=nxt[i]){
if(to[i]==h){val[i]=id;return;}
}
to[++tot]=h;nxt[tot]=head[h%hs];head[h%hs]=tot;
val[tot]=id;
}
inline int get(int h){
for(int i=head[h%hs];i;i=nxt[i]){
if(to[i]==h) return val[i];
}return 0;
}
inline void itia(){tot=0;memset(head,0,sizeof(head));}
inline ll fp(ll a,int b)
{ll ret=1;for(;b;b>>=1,a=a*a%mod) if(b&1) ret=ret*a%mod;return ret;}
int main(){
while(scanf("%lld%lld%lld",&mod,&b,&n)==3){
b%=mod;
if(b==0){if(n==1) printf("0\n");else printf("no solution\n");continue;}
itia();
lim=(int)sqrt((double)mod)+1;
ll now=n%mod;
for(int i=1;i<=lim;i++){now=now*b%mod;insert(now,i);}
ll bri=fp(b,lim);now=1;int ptr=1;
for(int u,i=1;i<=lim;i++){
now=now*bri%mod;
if(u=get(now)){ptr=0;printf("%lld\n",((i*lim-u)%mod+mod)%mod);break;
}else if(now%mod==n){ptr=0;printf("%lld\n",((i*lim)%mod+mod)%mod);break;}
}
if(ptr) printf("no solution\n");
}
return 0;
}
ps:
顺便附一个拓展欧几里得:
#include<bits/stdc++.h>
using namespace std;
int a,b,x,y;
inline void excg(int a,int b)
{
if(b){
excg(b,a%b);
int k=x;x=y;y=k-a/b*y;
}else{x=1,y=0;}
}
int main(){
scanf("%d%d",&a,&b);
excg(a,b);
printf("%d\n",a*x+b*y);
return 0;
}