Bzoj3122:多项式BSGS
根据鸽笼原理,在p次后一定循环,一眼BSGS。
发现他给的函数是个一次函数,一次函数有什么性质呢?f(f(x))还是一次函数,这样就能做了。
首先我们暴力预处理出f(f(f(x)))......sqrt(p)层的f(x)。
然后预处理出前sqrt(p)迭代后的值。
我们可以用exgcd求出如果让f(x)=t,我们需要的x值。
然后我们枚举用多少层迭代sqrt(p)后的f(x)即可。
注意特判一下a==0的情况,因为exgcd无法处理有0的参数。
为什么跑得如此之慢?可能我需要一个unordered_map,然而C++11不能用......
代码:
1 #include<cstdio> 2 #include<cmath> 3 #include<map> 4 typedef long long int lli; 5 using namespace std; 6 7 lli mod; 8 9 struct Poly { 10 lli k,b; 11 inline Poly inter(const Poly &t) { 12 return (Poly){t.k*k%mod,(t.b*k%mod+b)%mod}; 13 } 14 inline lli ite(const lli &x) { 15 return ( k * x % mod + b ) % mod; 16 } 17 }now,trans,sqr; 18 19 inline lli exgcd(lli a,lli b,lli &x,lli &y) { 20 if( !b ) { 21 x = 1 , y = 0; 22 return a; 23 } 24 lli ret = exgcd(b,a%b,y,x); 25 y -= ( a / b ) * x; 26 return ret; 27 } 28 29 inline lli getx(const Poly &p,const lli &t) { 30 lli x,y,rit; 31 exgcd(p.k,mod,x,y); 32 rit = ( t - p.b + mod ) % mod , x = ( x % mod + mod ) % mod; 33 return x * rit % mod; 34 } 35 36 inline lli bsgs(lli a,lli b,lli x,lli t) { 37 if( !a && !b ) return x == t ? 1 : -1; 38 map<lli,lli> mp; 39 int sq = ( (double) sqrt(mod) + 0.5 ) + 1; 40 sqr = now = (Poly){1,0} , trans = (Poly){a,b}; 41 for(int i=1;i<=sq;i++) { 42 if( mp.find(x) == mp.end() ) mp[x] = i; 43 x = trans.ite(x); 44 } 45 for(int i=1;i<=sq;i++) sqr = trans.inter(sqr); 46 for(int i=0;i<=sq;i++) { 47 lli tx = getx(now,t); 48 if( mp.find(tx) != mp.end() ) return mp[tx] + i * sq; 49 now = sqr.inter(now); 50 } 51 return -1; 52 } 53 54 int main() { 55 static int T; 56 static lli a,b,x,t; 57 scanf("%d",&T); 58 while(T--) { 59 scanf("%lld%lld%lld%lld%lld",&mod,&a,&b,&x,&t); 60 printf("%lld\n",bsgs(a,b,x,t)); 61 } 62 return 0; 63 }