2019牛客多校第五场generator2——BSGS&&手写Hash

题目

几乎原题 BZOJ3122题解

分析

先推一波公式,然后除去特殊情况分类讨论,剩下就是形如 $a^i \equiv b(mod \ p)$ 的方程,可以使用BSGS算法。

在标准的BSGS中,内外层循环都是 $\sqrt p$,题目查询 $m$ 次,$m \leq 1000$,$ p \leq 10^9$,这样总时间复杂度为 $O(m \sqrt p)$,勉强能接受。据说使用读入优化和手写哈希还是能过得,可见Cls的代码%%%

仔细想一下,由于BSGS分成两步,其中第一步是建立 $a$ 的幂次方的表,而题恰好是 $a,p$相同下的一组询问,所以这一部分可以与处理。

显然,我们应该对这部分分大点,第二步就会小写(因为积一定),

如分成 $\sqrt {mp} \times \sqrt{\frac{p}{m}}$(前面是预处理时间,后面是每次查询的时间)

也可以是 $\frac{p}{1000} \times 1000$,总之,要是预处理部分大一点。

#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define per(i,a,n) for(int i=n;i>=a;i--)
#define pb push_back
#define mp make_pair
#define FI first
#define SE second
#define maxn 100000
#define inf 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
typedef vector<int> vi;
typedef double db;
  
int mod;
int m=1000;
  
const int M=12000005;
int hs[M],head[M],nxt[M],id[M],top;
void insert(int x,int y)
{
    int k=x%M;
    hs[top]=x,id[top]=y,nxt[top]=head[k],head[k]=top++;
}
int find(int x)
{
    int k=x%M;
    for(int i=head[k];i!=-1;i=nxt[i]) if(hs[i]==x) return id[i];
    return -1;
}
  
int BSGS(int a,int b,int n)
{
    if(b==1) return 0;
    ll p=1;
    int ans=inf;
    rep(i,0,m)
    {
        int id=find(1ll*p*b%n);
        if(id!=-1) ans=min(ans,id-i);
        p=p*a%mod;
    }
    if(ans==inf) return -1;
    return ans;
}
  
ll qp(ll a,ll k)
{
    ll res=1;
    while(k)
    {
        if(k&1) res=res*a%mod;
        a=a*a%mod;
        k>>=1;
    }
    return res;
}
ll _inv(ll x) {return qp(x,mod-2);}
  
int main()
{
    int CAS; scanf("%d",&CAS);
    while(CAS--)
    {
        ll N; int x0,a,b; scanf("%lld%d%d%d%d",&N,&x0,&a,&b,&mod);
        memset(head,-1,sizeof head); top=1;
  
        int bn=(mod+m-1)/m;
        int aA=qp(a,m),pw=aA;
        rep(i,1,bn)
        {
            if(find(pw)==-1) insert(pw,i*m);
            pw=1ll*pw*aA%mod;
        }
        int Q; scanf("%d",&Q);
        while(Q--)
        {
            int v; scanf("%d",&v);
            if(a==0)
            {
                if(v==x0) puts("0");
                else if(v==b)
                {
                    if(N==1) puts("-1");
                    else puts("1");
                }
                else puts("-1");
            }
            else if(a==1)
            {
                if(b==0)
                {
                    if(v==x0) puts("0");
                    else puts("-1");
                }
                else
                {
                    ll n=1ll*(v+mod-x0)*_inv(b)%mod;
                    if(n>=N) puts("-1");
                    else printf("%lld\n",n);
                }
            }
            else
            {
                v=(1ll*(a-1)*v+b)%mod;
                int X=(1ll*(a-1)*x0+b)%mod;
                if(X==0)
                {
                    if(v==0) puts("0");
                    else puts("-1");
                }
                else
                {
                    v=1ll*v*_inv(X)%mod;
                    if(v==0) puts("-1");
                    else
                    {
                        int n=BSGS(a,v,mod);
                        if(n>=N) puts("-1");
                        else printf("%d\n",n);
                    }
                }
            }
        }
    }
    return 0;
}

参考链接:https://ac.nowcoder.com/acm/contest/view-submission?submissionId=41008097

猜你喜欢

转载自www.cnblogs.com/lfri/p/11286172.html