BZOJ3122 SDOI2013 随机数生成器 BSGS
题意:${x_{i + 1}} = (a{x_i} + b)\bmod p$,求最小的n使xn=t,无解输出-1,保证p为质数。
题解:
学好数理化,走遍天下都不怕
显然有\[{x_n} = {a^{n - 1}}{x_1} + b\sum\limits_{i = 0}^{n - 2} {{a^i}} = {a^{n - 1}}{x_1} + \frac{{b({a^{n - 1}} - 1)}}{{a - 1}} \equiv t(\bmod p)\]
设a-1的逆元为c,代入整理后得到\[{a^{n - 1}} = (bc + t){({x_1} + bc)^{ - 1}}\bmod p\]
BSGS求a即可。注意有些特殊情况
①、x1==t的时候n=1
②、a==0的时候看b是否等于t
③、a==1的时候原式可以化为t=x1+(n-1)b,exgcd求解不解释
#include<map> #include<cmath> #include<cstdio> #include<iostream> #include<algorithm> #define ll long long using namespace std; int T; ll p,a,b,x1,t; map<ll,int> table; map<ll,int>::iterator it; ll exgcd(ll a,ll b,ll &x,ll &y){ if(!b){ x=1;y=0; return a; } ll tmp=exgcd(b,a%b,x,y),t=x; x=y,y=t-a/b*y; return tmp; } ll Quick_pow(ll a,ll b,ll p){ a%=p; ll t=(b&1?a:1); while(b>>=1){ a*=a,a%=p; if(b&1) t*=a,t%=p; } return t; } ll bsgs(ll A,ll B,ll C){ table.clear(); A%=C; if(!A){ if(!B) return 1; else return -1; } ll m=ceil(sqrt(C)),t=1,tmp=1,x,y,ans=-1; for(int i=0;i<m;i++,t=(t*A)%p) table[t]=i; for(int i=0;i<m;i++){ exgcd(tmp,C,x,y); x=((x*B)%C+C)%C; it=table.find(x); if(it!=table.end()){ ans=i*m+it->second; break; } tmp=(tmp*t)%C; } if(ans==-1) return -1; return ans; } ll cal1(){ ll C=(t-x1+p)%p,x,y,t=exgcd(b,p,x,y); if(C%t) return -1; C/=t; x=x*C%p; if(x<0) x+=p; return x+1; } ll cal2(){ ll c=Quick_pow(a-1,p-2,p),A=(x1+b*c)%p,C=(t+b*c)%p,x,y,t=exgcd(A,p,x,y); if(C%t) return -1; C/=t; if(x<p) x=x%p+p; t=bsgs(a,x*C%p,p); if(t!=-1) return t+1; return -1; } ll solve(){ if(x1==t) return 1; if(!a){ if(b==t)return 2; return -1; } if(a==1) return cal1(); return cal2(); } int main(){ cin >> T; while(T--){ scanf("%d %d %d %d %d",&p,&a,&b,&x1,&t); cout << solve() << endl; } return 0; }