[SDOI2013]随机数生成器

洛咕 BZOJ

题意:对于线性递推式\(X_{i+1}≡aX_i+b(\mod p)\),给定\(p,a,b,X_1,t\),求最小的\(i\)满足\(X_i=t\)或者判断无解.

分析:考虑对递推式子进行转化,

\(X_{i}=aX_{i-1}+b=a(X_{i-2}+b)+b\)

\(=...=a^{i-1}X_1+b+ab+a^2b+...+a^{i-2}b\)

\(=a^{i-1}X_1+\frac{b(a^{i-1}-1)}{a-1}=t\)

式子中只有\(a^{i-1}\)是未知量,而我们要求的就是\(i\),所以考虑把\(a^{i-1}\)单独拎出来,得到\(a^{i-1}≡\frac{(a-1)t+b}{(a-1)X_1+b}(\mod p)\)

所以就可以直接套BSGS了.但因为右边是个分式,所以需要特判几种情况.

1、若\(X_1=t\),分式的值为1,所以\(i=1\);

2、若\(a=0\),如果\(b=t\),分式的值为0,所以\(i=2\),否则无解,输出\(-1\);

3、若\(a=1\),如果\(b=0\),分式无解,输出\(-1\),否则有式子\(X_1+nb≡t(\mod p)\),直接求\(t-X_1\)乘b的逆元即可.

#include<bits/stdc++.h>
using namespace std;
inline int read(){
   int s=0,w=1;char ch=getchar();
   while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
   while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
   return s*w;
}
inline int ksm(int a,int b,int c){
    int cnt=1;
    while(b){
		if(b&1)cnt=(1ll*cnt*a)%c;
		a=(1ll*a*a)%c;
		b>>=1;
    }
    return cnt;
}
map<int,int>ha;
inline int BSGS(int a,int b,int p){
    if(a%p==0)return -2;
    ha.clear();
    int t=sqrt(p)+1,x=b,y=ksm(a,t,p);
    for(int i=0;i<=t;i++){ha[x]=i;x=1ll*x*a%p;}
    x=y;
    for(int i=1;i<=t;i++){
		if(ha.count(x))return i*t-ha[x];
		x=1ll*x*y%p;
    }
    return -2;
}
int main(){
    int T=read();
    while(T--){
		int p=read(),a=read(),b=read(),x1=read(),t=read();
		if(x1==t){puts("1");continue;}
		if(a==0){
        	if(b==t)puts("2");
            else puts("-1");
            continue;
        }
		if(a==1){
        	if(b==0)puts("-1");
            else printf("%lld\n",1ll*ksm(b,p-2,p)*(t-x1+p)%p+1);
            continue;
        }
		int c=1ll*b*ksm(a-1,p-2,p)%p;
        int d=1ll*(t+c)*ksm(x1+c,p-2,p)%p;
		printf("%d\n",BSGS(a,d,p)+1);
    }
    return 0;
}

posted on 2019-05-04 11:53  PPXppx  阅读(105)  评论(0编辑  收藏  举报