输入含有多组数据,第一行一个正整数T,表示这个测试点内的数据组数。
接下来T行,每行有五个整数p,a,b,X1,t,表示一组数据。保证X1和t都是合法的页码。
注意:P一定为质数
共T行,每行一个整数表示他最早读到第t页是哪一天。如果他永远不会读到第t页,输出-1。
0<=a<=P-1,0<=b<=P-1,2<=P<=10^9
题解:这是一道不错的数论题,困扰了我好久,最终AC了。
如果问我做这道题最大的感慨是什么的话
1.数论太神啦
2.没事就取模,内存够果断开long long (因为炸飞调了好久)
这道题要分情况讨论,所以有很多看似很简单,但很不容易想全的特判
1.x1==t ,直接输出1
2.a==0 (1)b==t 输出2
(2)否则输出-1
3.a==1
式子就可以化简成
xn=x1+(ans-1)b mod p
整理得 xn-x1=(ans-1)b mod p
令 z=xn-x1, x=ans-1
bx=z mod p
即 bx+mp=z 其中b,p,z 为已知,就可以用扩张欧几里德先求bx+mp=1 的解再乘z
当然也可以 ans-1 =(xn-x1)*inv(b) ,inv(b)表示b 的逆元,在模意义下,除以b等于乘b的逆元。
根据费马小定理 a,p 互质,p为质数 a^p-1=1 mod p ,ax=1 mod p a的逆元x=a^p-2;
4. 将原式化简
x[i+1]=ax[i]+b(mod p)
x[i+1]+b/(a-1)=a(x[i]+b/(a-1))] (mod p) 把 x[i+1]=ax[i]+b mod p代入得
x[n]+b/(a-1)=a^(n-1)(x1+b/(a-1)) (mod p) x[n]=t
(t+b*inv(a-1))*inv(x1+b*inv(a-1))=a^(n-1)(mod p) inv
整理可得 a^x=z mod p x=n-1, z=(t+b*inv(a-1))*inv(x1+b*inv(a-1))这样就可以用bsgs求解
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<map> using namespace std; long long a,b,p,t,x,n,z,ax,ay; map<long long,long long> mp; void exgcd(long long a,long long b) { if (b==0) { ax=1; ay=0; return; } else { exgcd(b,a%b); long long t=ay; ay=ax-(a/b)*ay; ax=t; } } long long gcd(long long x,long long y) { long long r=0; while(y!=0) { r=x%y; x=y; y=r; } return x; } long long quickpow(long long num,long long x) { long long k=num%p; long long ans=1; while (x>0) { if (x&1) ans=(ans*k)%p; x=x>>1; k=(k*k)%p; } return ans; } int main() { freopen("input.in","r",stdin); freopen("output.out","w",stdout); scanf("%d",&n); for (int l=1;l<=n;l++) { bool pd=false; scanf("%I64d%I64d%I64d%I64d%I64d",&p,&a,&b,&x,&t); if(x==t) { printf("1\n"); continue; } if (a==0) if (b==t) { printf("2\n"); continue; } else { printf("-1\n"); continue; } if (a==1) { z=((t-x)%p+p)%p; if (z%(gcd(b,p))!=0) { printf("-1\n"); continue; } exgcd(b,p); ax=(ax%p*z%p)%p; printf("%d\n",(ax%p+p)%p+1); continue; } long long inva=quickpow(a-1,p-2)%p; long long invb=quickpow(x+b*inva,p-2)%p; long long nk=(long long)((t+b*inva)%p*invb%p)%p; mp.clear(); long long ans=nk; long long m=ceil(sqrt(p)); mp[ans%p]=0; for (long long i=1;i<=m;i++) { ans=(long long)(ans%p*a%p)%p; mp[ans]=i; } long long an=quickpow(a,m); ans=1; for(long long i=1;i<=m;i++) { ans=(long long)(ans%p*an%p)%p; if (mp[ans]) { printf("%d\n",((i*m-mp[ans])%p+p)%p+1); pd=true; break; } } if (!pd) printf("-1\n"); } }