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 }
View Code

 

转载于:https://www.cnblogs.com/Cmd2001/p/8663021.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值