BZOJ 3122 SDOI2013 随机数生成器
一大堆边界一开始并不知道,胡乱判了几个之后一直WA
无奈之下只好去下载了数据,然后就疯狂判各种奇怪的边界了
刨去边界问题
首先我们考虑a=1的情况
x1+k*b=t(mod p)
ex_gcd即可解
考虑a>1的情况
令S=X+b/(a-1)
原式就变成了一个等比数列
即S1*a^k=(t+b/(a-1))(mod p)
移项之后BSGS解即可
其他边界都可以O(1)判断
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cstdlib> #include<map> #include<cmath> using namespace std; typedef long long LL; int T; LL p,a,b,x1,x,y,d,t,inv; map<LL,int>Q; void ex_gcd(LL a,LL b,LL &d,LL &x,LL &y){ if(b==0){x=1;y=0;d=a;return;} ex_gcd(b,a%b,d,y,x);y-=(a/b)*x; } LL pow_mod(LL v,LL b){ LL tmp=1; while(b){ if(b&1)tmp=tmp*v%p; v=v*v%p;b>>=1; }return tmp; } LL log_mod(LL a,LL b,LL n){ if(a==0&&b==0)return 1; if(a==0)return -1; LL m=(int)(sqrt(n+0.5))+1;Q.clear(); LL v=pow_mod(a,m);v=pow_mod(v,n-2); LL e=1;Q[1]=0; for(int i=1;i<m;++i){ e=e*a%n; if(!Q.count(e))Q[e]=i; } for(int i=0;i<m;++i){ if(Q.count(b))return i*m+Q[b]+1; b=b*v%n; }return -1; } int main(){ scanf("%d",&T); while(T--){ scanf("%lld%lld%lld%lld%lld",&p,&a,&b,&x1,&t); if(x1==t){printf("1\n");continue;} if(a==0){ if(b==t){printf("2\n");continue;} else {printf("-1\n");continue;} } if(a==1){ if(b==0){printf("-1\n");continue;} ex_gcd(b,p,d,x,y); x1=(t-x1+p)%p; if(x1%d!=0){printf("-1\n");continue;} x=x*x1; x=(x%p+p)%p; printf("%lld\n",x+1); continue; } inv=pow_mod(a-1,p-2); b=b*inv%p; x1=(x1+b)%p;t=(t+b)%p; x1=pow_mod(x1,p-2); t=t*x1%p; printf("%lld\n",log_mod(a,t,p)); }return 0; }