bzoj3122 随机数生成器 BSGS+费马小定理求逆元

来源:互联网 发布:程序员试用期转正申请 编辑:程序博客网 时间:2024/05/29 03:41

这里写图片描述

这道题应该算是数论里面比较难的一道题,我顺便借此学了BSGS(Baby Steps Giant Steps),又称力拔盖世算法(手动滑稽).刚开始看到这道题只能感到深深的无助,完全不会做…对于一道数论题如果不会做的话,大家还是可以尝试很多特判骗分的,这道题就有很多特判.从小角度切入,深入了解问题,往往是很重要的.
由于不知道怎么打出一堆数学符号,所以很难与大家分享我的题解。我在网上找了另一个人的博客,他这道题讲的很清晰,我学BSGS也是从他那里学来的,希望大家能够学会。这篇博客就当提供一段简洁明了,逻辑清晰的代码(真的挺短,只用了费马小定理通过快速幂求逆元).
BSGS:http://blog.csdn.net/clove_unique/article/details/50740412
bzoj3122:http://blog.csdn.net/clove_unique/article/details/50776001

#include<stdio.h>#include<map>#include<cmath>using namespace std;typedef long long dnt;map<dnt,dnt> has;dnt p,a,b,x1,t,T,ny,nia,ans,oops;inline const dnt read(){    register dnt f=1,x=0;    register char ch=getchar();    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}    while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}    return x*f;}inline dnt pow(dnt base,dnt tmp){    dnt a=1;    while(tmp){      if(tmp&1) a=a*base%p;      base=base*base%p;      tmp=tmp>>1;    }    return a;}inline dnt BSGS(dnt a,dnt b){    dnt m=ceil(sqrt(p)),am=pow(a,m),mul=1,val=b%p;    has.clear();    has[val]=0;    for(dnt j=1;j<=m;j++){        mul=mul*a%p;        val=mul*b%p;        has[val]=j;    }    mul=1;    for(dnt i=1;i<=m;i++){       mul=mul*am%p;       if(has[mul]) return i*m-has[mul]+1;    }    return -1;}int main(){    T=read();    while(T--){      p=read(),a=read(),b=read(),x1=read(),t=read();      if(t==x1) {printf("1\n");continue;}      if(!a){         if(b!=t) printf("-1\n");         else printf("2\n");         continue;      }      if(a==1){         if(!b) printf("-1\n");          else{            ny=pow(b,p-2);            ans=((t-x1)%p+p)%p*ny%p;            printf("%lld\n",ans+1);         }         continue;      }      nia=pow(a-1,p-2);      oops=(t+b%p*nia%p)%p*pow(x1+b%p*nia%p,p-2)%p;      printf("%lld\n",BSGS(a,oops));    }}
原创粉丝点击