POJ

Posted Mr_Wolfram的高维空间

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了POJ相关的知识,希望对你有一定的参考价值。

BSGS

用于求解形如 \(a^x \equiv b \pmod p\) 的高次同余方程的方法

BSGS(Baby Step, Giant Step), 大步小步(拔山盖世)

我们将 \(x\) 写成如下形式 $x = i * t - j $ 其中 \(t = \sqrt p\) , $ 0 \leq j \leq t$ (为了遍历到 \(x = 0\)的情况,所以我们使 \(j\) 可以等于 \(t\) ,当然也可以特判 $x = 0 $的情况)

所以原公式可化为 \[a ^ {i * t} \equiv b \times a^j \pmod p\]

我们可以预处理出 \(b \times a ^ j \pmod p\) 的所有值,存入Hash表(用map也可以,但是多一个log),如果对于两个不同的 \(j\) ,算下的值是一样的,因为我们要求的是最小的 \(x\) ,我们可以贪心的存最大的 \(j\) .

首先特判,\(a\) 是否是 \(p\) 的倍数,如果是根据 \(b\) 的值输出答案,
然后从小到大枚举 \(i\) ,计算 \(a^{i*t} \pmod p\),如果对于某个 \(i\) 来说,计算下的值在Hash表里面出现过,那么答案就是 \(i*t - j\)

根据欧拉定理 \(a^x \equiv a^{x + \varphi (p)} \pmod p\)
所以如果 \(x\) 没有出现在 \(\varphi (p)\) 的范围以内,那么就无解

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;
ll p, a, b, n, opt;
struct HashTable{
    static const int MOD = 99901, MAXN = 200005;
    ll head[MAXN], nxt[MAXN], dat[MAXN], id[MAXN], nume;
    void clear(){
        memset(head, 0, sizeof(head));
        memset(nxt, 0, sizeof(nxt));
        nume = 0;
    }
    void insert(ll x, ll y) {
        for(int i = head[x % MOD]; i ; i = nxt[i]){
            if(dat[i] == x) {id[i] = y;return;}
        }
        dat[++nume] = x;
        id[nume] = y;
        nxt[nume] = head[x % MOD];
        head[x % MOD] = nume;
    }
    ll query(ll x) {
        for(int i = head[x % MOD] ; i; i = nxt[i]) {
            if(dat[i] == x) return id[i];
        }
        return -1;
    }
}Hash;
ll quick_mod(ll n, ll k, ll p) {
    ll ans = 1;
    while(k) {
        if(k & 1ll) (ans *= n) %= p;
        (n *= n) %= p;
        k >>= 1;
    }
    return ans;
}
int main() {
    while(cin >> p >> a >> b){
        Hash.clear();
        ll t = ceil(sqrt(p));
        if(!(a % p)){
            if(b % p == 1) printf("0\n");
            else if(b % p == 0) printf("1\n");
            else printf("no solution\n");
            continue;
        }
        for(int i = 0 ; i <= t ; i++) {
            ll k = b * quick_mod(a, i, p) % p;
            Hash.insert(k, i);
        }
        ll ans = 1, tmp = quick_mod(a, t, p);
        bool f = 0;
        for(int i = 1; i <= t; i++) {
            (ans *= tmp) %= p;
            ll j = Hash.query(ans);
            if(j != -1) {f = 1; printf("%lld\n", i * t - j);break;}
        }
        if(!f) printf("no solution\n");
    }
    return 0;
}

以上是关于POJ的主要内容,如果未能解决你的问题,请参考以下文章

18.06.03 POJ 4126:DNA 15年程设期末05(状压DP)

poj 1011 sticks 解题。

贪心算法----区间覆盖问题(POJ2376)

POJ1699 Best Sequence(AC自动机+状压DP)

POJ-2752(KMP算法+前缀数组的应用)

POJ - 2778 ~ HDU - 2243 AC自动机+矩阵快速幂