一道ZHX的题 O (1) 快速乘 BSGS

大家都很强, 可与之共勉。

【题目描述】
HJA在和学弟学数学,于是便有了一道非常简单的数学题:求满足 的最小自然数x。
【输入格式】
输入数据一行三个正整数a、b、p,我们保证p是一个质数。
【输出格式】
一行一个整数代表最小的自然数x,如果不存在这样的x输出-1。
【样例输入】
2 1 3
【样例输出】
0
【数据范围与规定】
对于30%的数据,1≤p≤1000。
对于100%的数据,1 ≤ a,b < p ≤ 10^12。

题解
就是一个裸的BSGS,可是考完之后才会发现爆long long……

所以恶补了一下O ( 1 ) 的快速乘。

inline long long mmul ( const long long& a, const long long& b )  {
    long long lf = a * ( b >> 20 ) % p * ( 1LL << 20 ) % p ;
    long long rg = a * ( b & ( ( 1LL << 20 ) - 1 ) ) % p ;
    return ( lf + rg ) % p ;
}

Code :

# include <cmath>
# include <cstdio>
# include <cstring>

const long long Base = 100137 ;

struct Hash  {
    struct edge  {
        int nxt ; long long a ; int b ;
    } g [Base << 4] ;
    int head [Base], ecnt ;
    inline void Init ( )  {
        ecnt = 0 ;
        memset ( head, 0, sizeof head ) ;
    }
    inline void insert ( long long a, int b )  {
        long long key = a % Base ;
        for ( register int i = head [key] ; i ; i = g [i].nxt )
            if ( g [i].a == a ) return ;
        g [++ ecnt] = ( edge ) {  head [key], a, b  } ; head [key] = ecnt ;
    }
    inline long long query ( long long a )  {
        long long key = a % Base ;
        for ( register int i = head [key] ; i ; i = g [i].nxt )
            if ( g [i].a == a ) return g [i].b ;
        return -1 ;
    }
} hash ;

long long a, b, p ;

const long long AAA = 1LL << 20, BBB = AAA - 1 ;    long long CCC ;

inline long long mmul ( const long long& a, const long long& b )  {
    long long lf = a * ( b >> 20 ) % p * CCC ;
    long long rg = a * ( b & BBB ) % p ;
    return ( lf + rg ) % p ;
}

inline long long mpow ( register long long a, register long long x, register long long Mod )  {
    register long long rt ;
    for ( rt = 1 ; x ; x >>= 1, a = mmul ( a, a ) )
        if ( x & 1 ) rt = mmul ( rt, a ) ;
    return rt ;
}

inline long long Bsgs ( long long g, long long a, long long p )  {
    hash.Init ( ) ;
    int b = ( int ) ceil ( sqrt ( a ) ) ;
    register long long cur = 1 ;
    for ( register int i = 0 ; i < b ; ++ i, cur = mmul ( cur, g ) )  {
        if ( cur == a ) return i ;
        hash.insert ( cur, i ) ;
    }
    register long long base = mpow ( cur, p - 2, p ) ;
    cur = mmul ( base, a ) ;
    for ( register long long i = b ; i < p ; i += b, cur = mmul ( cur, base ) )  {
        long long j = hash.query ( cur ) ;
        if ( j ^ -1 ) return i + j ;
    }
    return -1 ;
}

int main ( ) {
    freopen ( "braveheart.in", "r", stdin ) ;
    freopen ( "braveheart.out", "w", stdout ) ;
    scanf ( "%I64d%I64d%I64d", & a, & b, & p ) ;
    CCC = AAA % p ;
    return printf ( "%I64d\n", Bsgs ( a, b, p ) ), 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值