2019牛客多校第五场C generator 2 hash,bsgs模板

generator 2

题意

给出\(x_0,a,b,p\),有方程\(x_i\equiv (a*x_{i-1}+b)(\% p)\),求最小的i,使得\(x_i=v\),不存在输出-1

分析

经过公式运算可以知道,当a!=1时,由等比数列求和我们可以知道,\(v=x_n=x_0*a^n+b*\frac{a^n-1}{a-1}\),化简得\(a^n\equiv \frac{(a-1)v+b}{(a-1)x0+b} (\% p)\) 这样就转化成了bsgs的形式,直接套用bsgs即可。这里需要注意的是,因为由q次询问,bsgs需要预处理没有询问参数v的一端,然后再在询问询问里面查找另外一段,这里考察的是活用bsgs,因为这和平常的bsgs是相反的,其次需要知道的是,使用unordered_map可以卡过去,但是稳一点还是手写hash
注意要特判左边算出来是1的情况
a=0和a=1也需要特判

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+3;
namespace Hash{
    const int maxn=1e6+3;
    int cnt,head[maxn],nxt[maxn];
    ll val[maxn],pos[maxn];
    void init(){
        cnt=0;
        memset(head,-1,sizeof(head));
    }
    void insert(ll x,ll y){
        ll tx=x%maxn;
        val[cnt]=x,pos[cnt]=y;
        nxt[cnt]=head[tx];
        head[tx]=cnt++;
    }
    ll get(ll x){
        ll tx=x%maxn;
        for(int i=head[tx];~i;i=nxt[i]){
            if(val[i]==x) return pos[i]; 
        }
        return -1;
    }
}
unordered_map<ll,ll>mp;
long long n,x0,a,b,p;
ll mul(ll a,ll b){return 1ll*a%p*b%p;}
ll fpow(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)ans=mul(ans,a);
        a=mul(a,a);
        b>>=1;
        //cout<<ans<<endl;
    }
return ans;
}
ll inv(ll x){
    return fpow(x,p-2);
}
ll add(ll a,ll b){return (a%p+b%p+p)%p;}
int main(){
    int t;
    scanf("%d",&t);
    while(t--){
        ll q,v;
        //mp.clear();
Hash::init();
        scanf("%lld%lld%lld%lld%lld",&n,&x0,&a,&b,&p);
        scanf("%lld",&q);
        ll m=sqrt(p)+1;
        ll t=fpow(a,m);
  ll  s=1;
        for(int i=1;i<=m;i++){
          /*  if(!mp.count(s)){
                mp[s]=i*m;
            }*/
            s=1ll*s*t%p;
        ll tp=Hash::get(s);
            if(tp==-1) Hash::insert(s,i*m);
        }
        while(q--){
            scanf("%lld",&v);
         //   mp.clear();
            if(a==0){
                if(x0==v)printf("0\n");
                else if(v==b)printf("1\n");
                else printf("-1\n");
            continue;
            }
            if(a==1){
                ll ans=((v-x0+p)%p)*inv(b)%p;
                if(ans<n)printf("%lld\n",ans);
                else printf("-1\n");
                continue;
            }
        ll y=mul(add(b,mul(v,a-1)),inv(((mul(a,x0)-x0+p)%p+b)%p));
        //cout<<"y "<<y<<endl;
        ll ans=p+1;
        ll  s=y;
        if(y==1){
            printf("0\n");
            continue;
        }
        for(int i=0;i<m;i++){
         /*   if(mp.count(s)){
                ans=min(ans,mp[s]-i);
            }*/
        ll tp=Hash::get(s);
                if(tp!=-1) ans=min(ans,tp-i);
            s=s*a%p;
        }
        if(ans>p||ans>=n)printf("-1\n");
        else printf("%lld\n",ans);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/ttttttttrx/p/11406593.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值