exBSGS

作用:求形如A^x==B(mod P)

考虑由BSGS----->exBSGS

BSGS:

(A与P互质)A^phi(P)==1(mod P),A^0==1(modP),感性理解,是个循环,

考虑分块,设A^(ky+b)==B(mod P)。

即(A^y)^k*A^b==B(mod P)------>A^b==B*inv((A^y)^k)(mod P);设y==sqrt(P);(phi(P)更好,但是P也行,主要是懒)

将A^g(0<=g<y)hash出,再每次判断即可。

exBSGS:

设 r=gcd(A,P),p=A/r,q=P/r;

首先考虑无解的情况(B%r!=0&&B!=1)

B=(r*p)^x+w*q*r=(r^x)*(p^x)+w*q*r=r*(r^(x-1))*p^x+r*q*w=r*(r^(x-1)*p^x+w*q);

若B==1,A^0==1;

所以,若(B%r!=0&&B!=1),则无解;

使A,P互质需要除去公因数,设b=B/r,

A*A^(x-1)==B(mod P)——>

P=q,B=b;

p*A^(x-1)==B(mod P)——>A^(x-1)=B*inv(p)(mod P);

循环此过程,直至A与P互质即可。

例题:https://www.luogu.org/problemnew/show/P4195

#include<cstdio>
#include<ctype.h>
#include<iostream>
#include<cmath>
using namespace std;
#define ll long long
inline ll rd()
{
    ll x=0,f=1;char c=getchar();
    while(!isdigit(c)){if(c=='-') f=-f;c=getchar();}
    while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
    return x*f;
}
const int N=1e5,mod=99991;
int P,vis[N],h[N],nxt[N],val[N];
ll exgcd(ll &x,ll &y,ll a,ll b)
{
    if(!b){x=1;y=0;return a;}
    int t=exgcd(x,y,b,a%b),w=x;x=y;y=w-(a/b)*x;
    return t;
}
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll bsgs(ll a,ll b,ll w)
{
    ll x,y,p=ceil(sqrt(P)),q,op=-1,i,j;exgcd(x,y,w,P);b=(b*x%P+P)%P;
    for(i=1,j=0;j<p;j++,i=i*a%P)  val[j+1]=i,x=i%mod,nxt[j+1]=h[x],h[x]=j+1;
    exgcd(x,y,i,P);q=(x%P+P)%P;
    for(i=b,j=0;j<=p;j++,i=i*q%P) {x=i%mod;for(y=h[x];y;y=nxt[y])if(val[y]==i)op=p*j+y-1;if(op!=-1) break;}
    for(i=1,j=0;j<p;j++,i=i*a%P) h[i%mod]=0;
    return op;
}
ll exbsgs(int a,int b)
{
    ll c,k=0,w=1;if(b==1) return 0;
    while((c=gcd(a,P))>1){if(b%c) return -1;b/=c;P/=c;w=w*(a/c)%P;k++;if(w==b) return k;}
    return (c=bsgs(a,b,w))==-1?-1:c+k;
}
int main()
{    
    while(1)
    {
        int a=rd(),b;ll c;P=rd();b=rd();if(!a&&!b&&!P) return 0;
        if((c=exbsgs(a,b))==-1) printf("No Solution\n");else printf("%lld\n",c);
    }
}

 

posted @ 2019-05-02 14:13  西白方丈  阅读(258)  评论(0编辑  收藏  举报