11.1 BSGS BZOJ 3239+2242

来源:互联网 发布:windows10基本软件 编辑:程序博客网 时间:2024/06/03 20:45

懒惰又有强迫症的KAKAYZ又来了。
我就知道DAY1一定是效率最高的,但愿可以坚持下去吧。
BSGS处理的是未知系数为指数的模意义方程,我就在这里简单推一推吧。
妈呀第一次用LaTeX还得慢慢学好麻烦哦>_<
以下所有推导均在modn意义下进行,式中不再注明。
首先是原方程

ax=b
根据欧拉定理,我们知道
aphi(n)=1
当然问题中n一般为素数,所以
phi(n)=n1
所以在模意义下方程如果存在解,那么
x{0,1,,n2}

如果枚举,那么毫无疑问这个复杂度是O(n),所以这就是BSGS算法大展身手的时候了。
首先我们定义一个m,设解
x=km+t
,先计算出a0,a1,,am1,并且开一个mapmap[ai]=i,可以把这个理解为x=km+t式中的t部分,之后我们枚举k
毫无疑问如果k是当前值,那么移项可得
at=bakm

看到这里相信所有人都没问题了吧,很简单就能知道当m=n复杂度最优,共计O(nlogn)

上代码:

BZOJ 3239

/**************************************************************    Problem: 3239    User: jialiang2508    Language: C++    Result: Accepted    Time:248 ms    Memory:3416 kb****************************************************************/#include <cstdio>#include <iostream>#include <map>#include <cmath>#define ll long longusing namespace std;int ty,tz,tp;map<ll,int>mp;ll power(ll a,ll b,ll p){    int res=1;    while(b){        if(b&1)res=res*a%p;        a=a*a%p,b>>=1;    }    return res;}int bsgs(ll a,ll b,ll p){    a%=p;    mp.clear();    if(!a){        if(!b)return 1;        else return -1;    }    int m=(int)ceil(sqrt((double)p));    ll e=1,v=power(a,p-m-1,p);    for(int i=1;i<m;i++){        e=e*a%p;        mp[e]=i;    }    for(int i=0;i<m;i++){        if(b==1)return i*m;        if(mp[b])return i*m+mp[b];        b=b*v%p;    }    return -1;}int main(){    //freopen("txt.in","r",stdin);freopen("txt.out","w",stdout);    while(~scanf("%d %d %d\n",&tp,&ty,&tz)){        int temp=bsgs(ty,tz,tp);        if(temp==-1)printf("no solution\n");        else printf("%d\n",temp);    }    return 0;}

BZOJ 2242

/**************************************************************    Problem: 2242    User: jialiang2508    Language: C++    Result: Accepted    Time:2212 ms    Memory:2816 kb****************************************************************/#include <cstdio>#include <cmath>#include <map>#define ll long longusing namespace std;map<ll,int>mp;int n,opt;ll ty,tz,tp;ll power(ll a,ll b,ll p){    ll res=1;    while(b){        if(b&1)res=res*a%p;        a=a*a%p,b>>=1;    }    return res;}void solve1(ll y,ll z,ll p){printf("%lld\n",power(y,z,p));}void exgcd(ll a,ll b,ll &d,ll &x,ll &y){    if(!b){        x=1,y=0,d=a;return ;    }    exgcd(b,a%b,d,y,x),y-=a/b*x;}void solve2(ll a,ll z,ll b){    ll d,x,y;    exgcd(a,b,d,x,y);    if(z%d!=0){        printf("Orz, I cannot find x!\n");        return ;    }    x=x*(z/d)%(b/d);    printf("%lld\n",(x+b/d)%(b/d));}void solve3(ll a,ll b,ll p){    a%=p;    mp.clear();    if(!a){        if(!b)printf("1\n");        else printf("Orz, I cannot find x!\n");        return ;    }    int m=(int)ceil(sqrt((double)p));    ll e=1,v=power(a,p-m-1,p);    for(int i=1;i<m;i++){        e=e*a%p;        if(!mp[e])mp[e]=i;    }    for(int i=0;i<m;i++){        if(b==1){printf("%lld\n",(ll)i*m);return ;}        if(mp[b]){printf("%lld\n",(ll)i*m+mp[b]);return ;}        b=b*v%p;    }    printf("Orz, I cannot find x!\n");}int main(){    //freopen("txt.in","r",stdin);freopen("txt.out","w",stdout);    scanf("%d %d\n",&n,&opt);    for(int i=1;i<=n;i++){        scanf("%lld %lld %lld\n",&ty,&tz,&tp);        if(opt==1)solve1(ty,tz,tp);        if(opt==2)solve2(ty,tz%tp,tp);        if(opt==3)solve3(ty,tz,tp);    }    return 0;}