「Luogu3306」[SDOI2013]随机数生成器
problem
Solution
我们来回忆一下数列递推公式求通项的方法
令Yi=Xi+a−1b,则有
Yi=aYi−1⇒Yi=ai−1Y1
于是题目转化为求解方程
t+a−1b≡ax−1(X1+a−1b)(modp)
⇒ax−1≡X1+a−1bt+a−1b(modp)
好的,这个东西我们只要用BSGS就可以了
End?
几个细节:
X1=t时,直接输出1
当a=0时,输出若b=t则输出2,否则无解,X1=t的情况已经特判
当a=1时,方程实际上为
(x−1)b≡t−X1(modp)
根据裴蜀定理判掉无解,然后直接算x−1即可
需要注意的是如果bt−X1=p,则不需要取模直接输出
True End
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
| #include <cstdio> #include <cstdlib> #include <cmath> #include <algorithm> #include <cstring> #include <iostream> #include <map> #define mp(x,y) (make_pair((x),(y))) #define inv(x) (fastpow((x),p-2)) using namespace std; typedef long long ll;
template <typename T>void read(T &t) { t=0;int f=0;char c=getchar(); while(!isdigit(c)){f|=c=='-';c=getchar();} while(isdigit(c)){t=t*10+c-'0';c=getchar();} if(f)t=-t; }
int T;
ll p,a,b,X1,t; ll m;
ll fastpow(ll a,ll b) { ll re=1,base=a; while(b) { if(b&1) re=re*base%p; base=base*base%p; b>>=1; } return re; }
map<ll,ll> rec; void Pre() { rec.clear(); ll tmp=1; for(register int i=0;i<m;++i,tmp=tmp*a%p) rec.insert(mp(tmp,i)); }
ll BSGS() { ll iatm=inv(fastpow(a,m)),tmp=1; for(register int i=0;i<m;++i,tmp=tmp*iatm%p) if(rec.find(b*tmp%p)!=rec.end()) return i*m+rec[b*tmp%p]; return -2; }
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a; }
int main() { read(T); while(T--) { read(p),read(a),read(b),read(X1),read(t); if(X1==t) { puts("1"); continue; } if(a==1) { t=(t-X1+p)%p; if(t%gcd(b,p)) puts("-1"); else printf("%lld\n",t*inv(b)+1==p?p:(t*inv(b)+1)%p); continue; } if(a==0) { printf("%lld\n",b==t?2:-1ll); continue; } b=b*inv(a-1)%p; b=(t+b)*inv(X1+b)%p; m=ceil(sqrt(p)); Pre(); printf("%lld\n",BSGS()+1); } return 0; }
|