YZOJ P3451 [SDOI2013]随机数生成器问题
时间限制:1000MS 内存限制:262144KB
难度:\(6.0\)
-
题目描述
有一个随机数生成器,可以生成 \(0\) ~ \(p-1\) 之间的伪随机整数。在生成之前,需要设定一个随机数种子 \(k\) (\(0 \leq k < p\)),则生成器第 \(1\) 次生成的整数为 \(k\)。该随机数生成器有 \(2\) 个参数 \(a, b\),如果第 \(i\) 次生成的整数为 \(x\),则第 \(i+1\) 次生成的整数为 \((ax+b) \bmod p\) 。
现给定整数 \(t\) ,我们的问题是,该随机数生成器至少需要生成多少个数,才能生成得到 \(t\)?
对于给定的 \(p,a,b,k,t\) ,请计算要使随机数生成器生成整数 \(t\),所需生成数的次数的最小值。
-
输入格式
多组数据。第一行一个整数 \(T\) 表示数据组数,\(T \leq 50\) 。
接下来 \(T\) 行,每行五个整数 \(p,a,b,k,t\) 表示一组数据,其中 \(0 \leq a,b,k,t < p\) 。
-
输出格式
对于每组数据,将随机数生成器的最小生成次数输出到文件中。
如果该随机数生成器无法生成整数 \(t\),输出 \(-1\) 。
-
样例输入
1 2 3 4 |
3 7 1 1 3 3 7 2 2 2 0 7 2 2 2 1 |
-
样例输出
1 2 3 |
1 3 -1 |
-
数据规模与约定
对于 \(20\%\) 的数据,\(p \leq 100\) 。
对于另外 \(30\%\) 的数据,\(a=1\) 。
对于另外 \(30\%\) 的数据,\(b=0\) 。
对于 \(100\%\) 的数据,\(p \leq 10^9\) 且 \(p\) 是质数。
稍微推一下式子就会发现这是模板题
可以把每一项都展开,找找规律,或者直接等比数列求和:
第 \(n\) 项为:\(a^{n-1}k-(a^{n-2}+a^{n-3}+…+a+1)b \bmod p\)
即:\(a^{n-1}k-\frac{a^{n-1}-1}{a-1} b \bmod p\)
令其同余于 \(t\) ,则有:
\(a^{n-1}k-\frac{a^{n-1}-1}{a-1} b\equiv t\pmod p\)
即:\(a^{n-1}\equiv \frac{t-\frac{b}{a-1}}{k-\frac{b}{a-1}}\pmod p\)
发现右边是常数,那就是一个 BSGS 了。
BSGS 一种比较好的写法:
有 \(a^n \equiv t (\bmod p)\) ,求 \(n\) 最小正整数解。
可以发现 \(n < p\) ,所以可以设 \(n=Ax-B\),其中 \(x=\lfloor \sqrt p \rfloor, 1 \leq A \leq x, 0 \leq B<x\) 。
所以 \(a^{Ax} \equiv t+a^B (\bmod p)\) ,用一个 hash_table
存值即可。
还有本题要特别注意 \(a=0\),\(a=1\) 的点,特判不清楚的话就。。。。。
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 |
#include <cstdio> #include <cstdlib> #include <cstring> #include <climits> #include <ext/pb_ds/assoc_container.hpp> #include <ext/pb_ds/hash_policy.hpp> inline int _gcd(register int a,register int b) { register int r=a%b; while(r) a=b,b=r,r=a%b; return b; } inline int _pow(register int base,register int b,const int&MOD) { base%=MOD; if(!base) return 0; register int ans=1; while(b) { if(b&1) ans=(long long)ans*base%MOD; base=(long long)base*base%MOD; b>>=1; } return ans; } __gnu_pbds::gp_hash_table<int,int> hash; int main() { int _T;scanf("%d",&_T); while(_T--) { int P,A,B,K,T;scanf("%d%d%d%d%d",&P,&A,&B,&K,&T); if(T==K) { printf("%d\n",1); continue; } if(A==0) { printf("%d\n",(B==T ? 2 : -1)); continue; } if(A==1) { if(B==0) printf("%d\n",-1); else printf("%lld\n",(long long)((T-K)%P+P)%P*_pow(B,P-2,P)%P + 1); continue; } if(_gcd(A,P) != 1) { printf("%d\n",-1); continue; } hash.clear(); register int sp=__builtin_sqrt(P); if(P%sp != 0) sp++; register int tv=(long long)B*_pow(A-1,P-2,P)%P; register int rov=(long long)(T+tv)%P*_pow(K+tv,P-2,P)%P; for(register int j=0;j<sp;j++) hash[(long long)rov*_pow(A,j,P)%P]=j+1; register int ans=0; for(register int i=1;i<=sp;i++) if((ans=hash[_pow(A,i*sp,P)])) { printf("%d\n",i*sp-(ans-1)+1); break; } if(ans<=0) printf("%d\n",-1); } return 0; } |