BSGS模板+牛客第三场D

BSGS是用来求解A^x ≡ B mod P (A,P互质)的最小非负正整数解的

ll gmod(ll a,ll b,ll p)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%p;
        a=a*a%p;b>>=1;
    }
    return res;
}
ll BSGS(ll y,ll z,ll p)
{
    unordered_map<ll,int> ha;
    if(y%p==0&&z!=0) return -1;
    if(y%p==0&&z==0) return 0;
    y%=p;z%=p;
    //if(z==1) return 0;  这题要找的是非0解
    ll m=(ll)sqrt(p)+1;
    for(int i=0,t=z;i<m;i++,t=1ll*t*y%p) ha[t]=i;
    for(int i=1,tt=gmod(y,m,p),t=tt;i<=m+1;++i,t=1ll*t*tt%p)
    {
        int k=ha.find(t)==ha.end()?-1:ha[t];
        if(k==-1) continue;
        return 1ll*i*m-k;
    }
    return -1;
}
ll gmod(ll a,ll b,ll p)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%p;
        a=a*a%p;b>>=1;
    }
    return res;
}
struct HashTable
{
    struct Line{int u,v,next;}e[1000000];
    int h[HashMod],cnt;
    void Add(int u,int v,int w){e[++cnt]=(Line){w,v,h[u]};h[u]=cnt;}
    void Clear(){memset(h,0,sizeof(h));cnt=0;}
    void Hash(int x,int k)
    {
        int s=x%HashMod;
        Add(s,k,x);
    }
    int Query(int x)
    {
        int s=x%HashMod;
        for(int i=h[s];i;i=e[i].next)
            if(e[i].u==x)return e[i].v;
        return -1;
    }
}ha;
ll BSGS(ll y,ll z,ll p)
{
    if(y%p==0&&z!=0) return -1;
    if(y%p==0&&z==0) return 0;
    y%=p;z%=p;ha.Clear();
    //if(z==1) return 0;  这题要找的是非0解
    ll m=(ll)sqrt(p)+1;
    for(ll i=0,t=z;i<m;i++,t=t*y%p) ha.Hash(t,i);
    for(ll i=1,tt=gmod(y,m,p),t=tt;i<=m+1;++i,t=t*tt%p)
    {
        ll k=ha.Query(t);
        if(k==-1) continue;
        return 1ll*i*m-k;
    }
    return -1;
}

这是大佬们手写的hash版本,感觉一般 unordered_map应该也够了,但是先存一下好了

以下是来源出处:https://www.cnblogs.com/cjyyb/p/8808166.html

附带牛客多校第三场的d:https://ac.nowcoder.com/acm/contest/883/D

这道题前面要求的其实就和洛谷的P4884一样,BSGS就行了,至于出题人题解写的模数为9*p,因为炸了ll,要用一下快速乘

#include <cstdio>
#include <cstdlib>
#include <cassert>
#include <cstring>
#include <bitset>
#include <cmath>
#include <cctype>
#include <iostream>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <sstream>
#include <iomanip>
#include <unordered_map>
using namespace std;
typedef long long ll;
typedef vector<long long> VI;
typedef unsigned long long ull;
const ll inff = 0x3f3f3f3f3f3f3f3f;
#define FOR(i,a,b) for(int i(a);i<=(b);++i)
#define FOL(i,a,b) for(int i(a);i>=(b);--i)
#define SZ(x) ((long long)(x).size())
#define REW(a,b) memset(a,b,sizeof(a))
#define inf int(0x3f3f3f3f)
#define si(a) scanf("%d",&a)
#define sl(a) scanf("%lld",&a)
#define sd(a) scanf("%lf",&a)
#define ss(a) scanf("%s",a)
#define mod ll(1e9+7)
#define pb push_back
#define eps 1e-6
#define lc d<<1
#define rc d<<1|1
#define Pll pair<ll,ll>
#define P pair<int,int>
#define pi acos(-1)
ll n,m,p,zz,er,ans;
ll gmod(ll a,ll b,ll p)
{
    ll res=1;
    while(b)
    {
        if(b&1) res=res*a%p;
        a=a*a%p;b>>=1;
    }
    return res;
}
ll BSGS(ll y,ll z,ll p)
{
    unordered_map<ll,ll> ha;
    if(y%p==0&&z!=0) return -1;
    if(y%p==0&&z==0) return 0;
    y%=p;z%=p;
    //if(z==1) return 0;  这题要找的是非0解
    ll m=(ll)sqrt(p)+1;
    for(ll i=0,t=z;i<m;i++,t=t*y%p) ha[t]=i;
    for(ll i=1,tt=gmod(y,m,p),t=tt;i<=m+1;++i,t=t*tt%p)
    {
        ll k=ha.find(t)==ha.end()?-1:ha[t];
        if(k==-1) continue;
        return 1ll*i*m-k;
    }
    return -1;
}
vector<P>g;
int main()
{
    cin.tie(0);
    cout.tie(0);
    int t,qw=0;
    cin>>t;
    while(t--)
    {
        cin>>p>>n>>m;
        if(p==2||p==5) {puts("0");continue;}
        zz=BSGS(10,1,p);
        if(p==3) zz=3;
        //cout<<zz<<endl;
        g.clear();er=1;ans=0;
        for(int i=2;i*i<=zz;i++)
        {
            if(zz%i==0)
            {
                qw=0;er*=i;
                while(zz%i==0) qw++,zz/=i;
                g.pb(P(i,qw));
            }
        }
        if(zz!=1) er*=zz;g.pb(P(zz,1));
        if(m>=35) ans+=(m-35)*(n/er),m=35;
        FOR(i,1,m)
        {
            er=1;
            for(int j=0;j<g.size();j++)
            {
                zz=(g[j].second+i-1)/i;
                while(zz--) er*=g[j].first;
            }
            ans+=(n/er);
        }
        cout<<ans<<endl;
    }
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值