[SDOI2013]随机数生成器-题解
题目地址【IN】
很久没写BSGS了,找个板子练练手吧
- 简略题意:
给你初始的,生成一个无限长的序列,序列的每个元素满足,询问你一个数字,最早在序列的哪个位置出现,输出位置,如果没有出现则输出。
首先推一波式子:
我们现在就的到了这个序列的通项公式,然后用等比数列求和公式简化一下,得到:
题外话:证明为的倍数(当a为正整数)
因为
展开后面就变成了,中间消掉就变成了,又因为为正整数,所以成立。
原式就变成了如下:
移个项,得到:
令右边为,原式就为。
现在我们相当于知道了,然后去求是否存在一个使其满足,就变成了板子题了。(不会BSGS的先去学,全称叫离散对数的大步小步算法)
但是注意,由于式子分母不能为所以特判,等比数列中的等比值时也要特判。
复杂度
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
int T;
ll P,a,b,X1,t;
namespace HASH_LIST{
const int M=1e5+10,Mod=91799;
struct ss{
int to,last;ll v,p;
ss(){}
ss(int a,int b,ll c,ll d):to(a),last(b),v(c),p(d){}
};
struct Hash_List{
ss g[M];
int head[M],cnt,tot;
void add(int a,int b,ll c,ll d){g[++cnt]=ss(b,head[a],c,d);head[a]=cnt;}
void clear(){memset(head,0,sizeof(head));cnt=tot=0;}
void insert(ll a,ll b){
int t=a%Mod;
add(t,++tot,a,b);
}
ll find(ll a){
int t=a%Mod;
for(int i=head[t];i;i=g[i].last){
if(g[i].v==a) return g[i].p;
}
return -1;
}
};
ll fpow(ll a,ll b,ll c){
ll res=1;
for(;b;b>>=1,a=(a*a)%c){
if(b&1)res=(res*a)%c;
}
return res;
}
ll exgcd(ll a,ll b,ll &x,ll &y){
if(!b){x=1;y=0;return a;}
ll t=exgcd(b,a%b,y,x);
y-=(a/b)*x;return t;
}
ll Inv(ll a,ll b){
ll xx,yy;
exgcd(a,b,xx,yy);
return (xx%b+b)%b;
}
ll gcd(ll a,ll b){
return b?gcd(b,a%b):a;
}
}
using namespace HASH_LIST;
Hash_List mp;//手写hash表
ll BSGS(ll a,ll b){
mp.clear();
ll now=(ll)sqrt(P)+1;
ll res=b;
for(ll i=1;i<=now;i++){
res=res*a;if(res>=P)res%=P;
mp.insert(res,i);
}
a=fpow(a,now,P);
if(!a){return !b?1:-1;}
res=1;ll ans=0;
for(ll i=1;i<=now;i++){
res=res*a;if(res>=P)res%=P;
ll tt=mp.find(res);
if(tt>=0){
ans=(i*now-tt)%P;if(ans<0)ans+=P;
return ans;
}
}
return -1;
}
int main(){
for(scanf("%d",&T);T--;){
scanf("%lld%lld%lld%lld%lld",&P,&a,&b,&X1,&t);
if(X1==t%P){puts("1");continue;}
if(!b){
ll val=t*Inv(X1,P)%P;
ll ans=BSGS(a,val);
if(ans==-1) puts("-1");
else printf("%lld\n",ans+1);
continue;
}
if(!a){
if(t%P==b)puts("2");else puts("-1");
}else if(a==1){
ll day=(t-X1)*Inv(b,P)%P;
if(day<0)(day%=P)+=P;
printf("%lld\n",day+1);
}else{
ll Inv_a=b*Inv(a-1,P)%P;
ll val=((t+Inv_a)%P)*Inv((X1+Inv_a)%P,P)%P;
ll ans=BSGS(a,val);
if(ans==-1) puts("-1");
else printf("%lld\n",ans+1);
}
}
return 0;
}
代码略丑,见谅。
其他关于以及的题目: