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 。
|
3 7 1 1 3 3 7 2 2 2 0 7 2 2 2 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; } |