【BSGS】POJ2417[Discrete Logging]&POJ3243[Clever Y]題解
阿新 • • 發佈:2019-01-02
POJ2417
題目概述
求滿足
解題報告
這就是經典的BSGS,由於要求最小的,所以雜湊表儲存時刷個小的就行了。
示例程式
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXINT=((1<<30)-1)*2+1;
int A,B,C;
struct Hashmap //雜湊表代替map
{
static const int Ha=999917,maxe=46340;
int E,lnk[Ha],son[maxe+5],nxt[maxe+5],w[maxe+5];
int top,stk[maxe+5];
void clear() {E=0;while (top) lnk[stk[top--]]=0;}
void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];w[E]=MAXINT;lnk[x]=E;}
bool count(int y)
{
int x=y%Ha;
for (int j=lnk[x];j;j=nxt[j])
if (y==son[j]) return true;
return false;
}
int& operator [] (int y)
{
int x=y%Ha;
for (int j=lnk[x];j;j=nxt[j])
if (y==son[j]) return w[j];
Add(x,y);stk[++top]=x;return w[E];
}
};
Hashmap f;
int exgcd(int a,int b,int &x,int &y)
{
if (!b) {x=1;y=0;return a;}
int r=exgcd(b,a%b,x,y),t=x;x=y;y=t-a/b*y;
return r;
}
int BSGS(int A,int B,int C)
{
if (C==1) if (!B) return A!=1; else return -1;
if (B==1) if (A) return 0; else return -1;
if (A%C==0) if (!B) return 1; else return -1; //幾種特判
int m=ceil(sqrt(C)),D=1,Base=1;f.clear();
for (int i=0;i<=m-1;i++) //先把A^j存進雜湊表
{
f[Base]=min(f[Base],i);
Base=((LL)Base*A)%C;
}
for (int i=0;i<=m-1;i++)
{
int x,y,r=exgcd(D,C,x,y);
x=((LL)x*B%C+C)%C; //擴歐求A^j
if (f.count(x)) return i*m+f[x]; //找到了
D=((LL)D*Base)%C;
}
return -1;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
while (~scanf("%d%d%d",&C,&A,&B))
{
int ans=BSGS(A,B,C);
if (ans==-1) printf("no solution\n"); else
printf("%d\n",ans);
}
return 0;
}
POJ3243
題目概述
求滿足
解題報告
經典的擴充套件BSGS。
示例程式
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
typedef long long LL;
const int MAXINT=((1<<30)-1)*2+1;
int A,B,C;
struct Hashmap
{
static const int Ha=999917,maxe=46340;
int E,lnk[Ha],son[maxe+5],nxt[maxe+5],w[maxe+5];
int top,stk[maxe+5];
void clear() {E=0;while (top) lnk[stk[top--]]=0;}
void Add(int x,int y) {son[++E]=y;nxt[E]=lnk[x];w[E]=MAXINT;lnk[x]=E;}
bool count(int y)
{
int x=y%Ha;
for (int j=lnk[x];j;j=nxt[j])
if (y==son[j]) return true;
return false;
}
int& operator [] (int y)
{
int x=y%Ha;
for (int j=lnk[x];j;j=nxt[j])
if (y==son[j]) return w[j];
Add(x,y);stk[++top]=x;return w[E];
}
};
Hashmap f;
int gcd(int a,int b) {if (!b) return a; else return gcd(b,a%b);}
int exgcd(int a,int b,int &x,int &y)
{
if (!b) {x=1;y=0;return a;}
int r=exgcd(b,a%b,x,y),t=x;x=y;y=t-a/b*y;
return r;
}
int exBSGS(int A,int B,int C)
{
if (C==1) if (!B) return A!=1; else return -1;
if (B==1) if (A) return 0; else return -1;
if (A%C==0) if (!B) return 1; else return -1;
int r,D=1,num=0;
while ((r=gcd(A,C))>1) //把A,C變成(A,C)=1為止
{
if (B%r) return -1;num++;
B/=r;C/=r;D=((LL)D*A/r)%C; //將多出來的乘給D
}
for (int i=0,now=1;i<num;i++,now=((LL)now*A)%C)
if (now==B) return i; //列舉0~num-1
int m=ceil(sqrt(C)),Base=1;f.clear();
for (int i=0;i<=m-1;i++)
{
f[Base]=min(f[Base],i);
Base=((LL)Base*A)%C;
}
for (int i=0;i<=m-1;i++)
{
int x,y,r=exgcd(D,C,x,y);
x=((LL)x*B%C+C)%C;
if (f.count(x)) return i*m+f[x]+num; //別忘了答案加num
D=((LL)D*Base)%C;
}
return -1;
}
int main()
{
freopen("program.in","r",stdin);
freopen("program.out","w",stdout);
while (~scanf("%d%d%d",&A,&C,&B))
{
if (!A&&!B&&!C) break;
int ans=exBSGS(A,B,C);
if (ans==-1) printf("No Solution\n"); else
printf("%d\n",ans);
}
return 0;
}