1. 程式人生 > >【BSGS】POJ2417[Discrete Logging]&POJ3243[Clever Y]題解

【BSGS】POJ2417[Discrete Logging]&POJ3243[Clever Y]題解

POJ2417

題目概述

求滿足AxB(mod C)的最小x,C是素數。

解題報告

這就是經典的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

題目概述

求滿足AxB(mod C)的最小x。

解題報告

經典的擴充套件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;
}