【bzoj3122】 Sdoi2013—随机数生成器
http://www.lydsy.com/JudgeOnline/problem.php?id=3122 (题目链接)
题意
对于一个数列${X_i}$,其递推式为:${X_{i+1}=(a*X_i+n)~mod~P}$,求最小的${i}$满足${X_i=t}$。
Solution
大家还记得数学中数列那一章吗,那么推倒这个数列的方法一定是老师重点强调过的:
$${X_{i+1}+λ=a*(X_i+λ)}$$
$${可以算出λ=\frac{b}{a-1}}$$
$${令B_i=X_i+\frac{b}{a-1}}$$
$${则B_{i+1}=a*B_i,为等比数列}$$
$${B_i=B_1*a^{i-1}}$$
$${B_i=(X_1+\frac{b}{a-1})*a^{i-1}}$$
$${\because B_i=X_i+\frac{b}{a-1}}$$
$${\therefore X_i=(X_1+\frac{b}{a-1})*a^{i-1}-\frac{b}{a-1}}$$
$${令c=(a-1)^{-1}~(mod~p)}$$
$${则X_i=(X_1+b*c)*a^{i-1}+b*c~~(mod~p)}$$
$${即求(X_1+b*c)*a^{i-1}≡t-b*c~~(mod~p)}$$
因为a的取值,我们需要考虑特殊情况并进行分类讨论。
首先要特判${X_1=t}$的情况,因为这个在后面不好处理,不如讨论之前就直接排除在外。
1.${a=0}$
这种情况下要么是${t=X_1}$,要么是${t=X_2}$,因为${X_n=b~(n>1)}$
2.${a=1}$
那么数列就可以简化为:${X_{i+1}=X_i+b}$,是一个等差数列。
即求:${X_1+b*(i-1)=t~(mod~p)}$
这可以用exgcd求解。
3.${a>=2}$
那么就是我们上面推下来的式子,先用exgcd求出${a^{i-1}}$的最小正整数解,然后用BSGS计算${i-1}$的取值。
细节
数学题就是细节多,exgcd判无解。
代码
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 | // bzoj3122 #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #include<cmath> #include<map> #define LL long long #define inf 2147483640 #define Pi acos(-1.0) #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout); using namespace std; map<LL,LL> mp; LL power(LL a,LL b,LL c) { LL res=1; while (b) { if (b&1) res=res*a%c; b>>=1;a=a*a%c; } return res; } LL BSGS(LL a,LL b,LL p) { LL m= ceil ( sqrt (p)); LL inv=power(a,p-1-m,p),e=1; mp.clear();mp[1]=0; for ( int i=1;i<m;i++) { e=e*a%p; if (!mp.count(e)) mp[e]=i; } for ( int i=0;i<m;i++) { if (mp.count(b)) return mp[b]+i*m+1; b=b*inv%p; } return -1; } void exgcd(LL a,LL b,LL &d,LL &x,LL &y) { if (b==0) {d=a;x=1;y=0; return ;} exgcd(b,a%b,d,y,x); y-=a/b*x; } int main() { LL P,A,B,X1,t; int T; scanf ( "%d" ,&T); while (T--) { scanf ( "%lld%lld%lld%lld%lld" ,&P,&A,&B,&X1,&t); if (X1==t) { puts ( "1" ); continue ;} //一定要特判,如果进入BSGS后b为0出来的解是-1 if (A==0) { if (B==t) puts ( "2" ); else puts ( "-1" ); } if (A==1) { LL x,d,y; t=(t-X1)%P; if (!t) { puts ( "1" ); continue ;} exgcd(B,P,d,x,y); if (t%d!=0) { puts ( "-1" ); continue ;} printf ( "%lld\n" ,((t/d)*x%(P/d)+(P/d))%(P/d)+1); } if (A>=2) { LL x,d,y; LL c=power(A-1,P-2,P); t=(t+B*c)%P; exgcd(X1+B*c,P,d,x,y); if (t%d!=0) { puts ( "-1" ); continue ;} x=((t/d)*x%(P/d)+(P/d))%(P/d); printf ( "%lld\n" ,BSGS(A,x,P)); } } return 0; } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步