poj 3243 Clever Y && 1467: Pku3243 clever Y【扩展BSGS】

时间:2023-03-10 05:04:13
poj 3243 Clever Y && 1467: Pku3243 clever Y【扩展BSGS】

扩展BSGS的板子

对于gcd(a,p)>1的情况

即扩展BSGS

把式子变成等式的形式: \( a^x+yp=b \)

设 \( g=gcd(a,p) \)

那么两边同时除以g就会变成: \( \frac{a}{g} a^{x-1}+y\frac{p}{g}=\frac{b}{g} \)

如此循环到ap互质,然后正常BSGS求即可

最后答案加上循环次数,即当前的x是经过几次减一得到的

注意有很多关于0和1的特判

以及这道题在bzoj上是可以用map的,但是poj上只能用hash

map版:

#include<iostream>
#include<cstdio>
#include<map>
#include<cmath>
using namespace std;
int a,b,p,ans;
map<int,int>mp;
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int ksm(int a,int b,int p)
{
int r=1;
while(b)
{
if(b&1)
r=(long long)r*a%p;
a=(long long)a*a%p;
b>>=1;
}
return r;
}
int BSGS(int a,int b,int p)
{
a%=p,b%=p;
if(b==1)
return 0;
int cnt=0,d=1;
for(int g=gcd(a,p);g!=1;g=gcd(a,p))
{
if(b%g)
return -1;
p/=g,b/=g;
d=(long long)d*a/g%p;
cnt++;
if(b==d)
return cnt;
}
mp.clear();
int m=ceil(sqrt(p)),t=b;
for(int i=0;i<m;i++)
{
mp[t]=i;
t=(long long)t*a%p;
}
int g=ksm(a,m,p);
t=(long long)d*g%p;
for(int i=1;i<=m+1;i++)
{
if(mp[t])
return cnt+i*m-mp[t];
t=(long long)t*g%p;
}
return -1;
}
int main()
{
while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
{
if(p==1)
{
puts("0");
continue;
}
ans=BSGS(a,b,p);
if(ans==-1)
puts("No Solution");
else
printf("%d\n",ans);
}
return 0;
}

hash版,大概比map*到四倍

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
const int mod=739391,N=2e6;
int a,b,p,ans,ti,v[N],con;
struct qwe
{
int b,v,ne;
}ha[N];
void ins(int w,int b,int va)
{//cout<<va<<endl;
if(v[w]!=ti)
{
v[w]=ti;
ha[w].v=va;
ha[w].b=b;
ha[w].ne=-1;
return;
}
for(;ha[w].ne!=-1;w=ha[w].ne)
if(ha[w].b==b)
return;
ha[w].ne=++con;
ha[con].ne=-1;
ha[con].v=va;
ha[con].b=b;
}
int find(int w,int b)
{
if(v[w]!=ti)
return 0;
for(;w!=-1;w=ha[w].ne)
if(ha[w].b==b)
return ha[w].v;
return 0;
}
int gcd(int a,int b)
{
return b==0?a:gcd(b,a%b);
}
int ksm(int a,int b,int p)
{
int r=1;
while(b)
{
if(b&1)
r=(long long)r*a%p;
a=(long long)a*a%p;
b>>=1;
}
return r;
}
int BSGS(int a,int b,int p)
{
a%=p,b%=p;
if(b==1)
return 0;
int cnt=0,d=1;
for(int g=gcd(a,p);g!=1;g=gcd(a,p))
{
if(b%g)
return -1;
p/=g,b/=g;
d=(long long)d*a/g%p;
cnt++;
if(b==d)
return cnt;
}
con=mod,ti++;
int m=ceil(sqrt(p)),t=b;
for(int i=0;i<m;i++)
{
ins(t%mod,t,i);
t=(long long)t*a%p;
}
int g=ksm(a,m,p),now;
t=(long long)d*g%p;
for(int i=1;i<=m+1;i++)
{
if(now=find(t%mod,t))
return cnt+i*m-now;
t=(long long)t*g%p;
}
return -1;
}
int main()
{
while(scanf("%d%d%d",&a,&p,&b)&&a+b+p)
{
if(p==1)
{
puts("0");
continue;
}
ans=BSGS(a,b,p);
if(ans==-1)
puts("No Solution");
else
printf("%d\n",ans);
}
return 0;
}